Introduction

The goal of this file is to lay out proof-of-concept analyses of the Strongyloides papillosus RNAseq dataset originally analyzed by Hunt et al 2016.

This dataset includes samples representing 5 life stages, each with 2 biological replicates: L1/L2s, FLF, FLM, iL3, PF.

Data Pre-Processing

A full description of Kallisto alignment and data filtering/normalization steps can be found in Sp_RNAseq_Data_Processing.rmd.

Data Analysis

The limma package ( Ritchie et al 2015, Phipson et al 2016) is used to conduct pairwise differential gene expression analyses between life stages. The results of the pairwise comparison is displayed as a volcano plot and interactive DataTable.

Code

All code is echoed under descriptive headers; code chunks are hidden from view by default. Users may show hidden R code by clicking the Show buttons. In addition, all code chunks are collated at the end of the document in an Appendix.

Load and Parse Preprocessed Data

This code loads R data objects that has been preproprocessed by Sp_RNAseq_Data_Processing.rmd.

# Load and Parse Preprocessed Data
load (file = "../Outputs/SpRNAseq_data_preprocessed")
targets <- SpRNAseq.preprocessed.data$targets
annotations <- SpRNAseq.preprocessed.data$annotations
log2.cpm.filtered.norm <- SpRNAseq.preprocessed.data$log2.cpm.filtered.norm
myDGEList.filtered.norm <-SpRNAseq.preprocessed.data$myDGEList.filtered.norm
Loading required package: edgeR
Loading required package: limma
rm(SpRNAseq.preprocessed.data)

load(file = "../Strongyloides_RNAseq_Browser/Data/Sp_vDEGList")

Hierarchical Clustering and Principle Components Analysis

This code chunk starts with filtered and normalized abundance data in a data frame (not tidy). It will implement hierarchical clustering and PCA analyses on the data. It will plot various graphs, including a dendrogram of the heirachical clustering, and several plots of visualize the PCA. Because the data that are passed into these analyses do not have batch correction applied, the clustering appears dominanted by a batch effect.

# Introduction to this chunk -----------
# This code chunk starts with filtered and normalized abundance data in a data frame (not tidy).
# It will implement hierarchical clustering and PCA analyses on the data.
# It will plot various graphs and can save them in PDF files.
# Load packages ------
suppressPackageStartupMessages({
  library(tidyverse) # you're familiar with this fromt the past two lectures
  library(ggplot2)
  library(RColorBrewer)
  library(ggdendro)
  library(magrittr)
  library(factoextra)
  library(gridExtra)
  library(cowplot)
  library(dendextend)
})

# Identify variables of interest in study design file ----
group <- factor(targets$group)

# Hierarchical clustering ---------------
# Remember: hierarchical clustering can only work on a data matrix, not a data frame

# Calculate distance matrix
# dist calculates distance between rows, so transpose data so that we get distance between samples.
# how similar are samples from each other
colnames(log2.cpm.filtered.norm)<-paste(targets$group,substr(targets$sample, 9,10), sep = ".")
distance <- dist(t(log2.cpm.filtered.norm), method = "maximum") #other distance methods are "euclidean", maximum", "manhattan", "canberra", "binary" or "minkowski"

# Calculate clusters to visualize differences. This is the hierarchical clustering.
# The methods here include: single (i.e. "friends-of-friends"), complete (i.e. complete linkage), and average (i.e. UPGMA). Here's a comparison of different types: https://en.wikipedia.org/wiki/UPGMA#Comparison_with_other_linkages
clusters <- hclust(distance, method = "complete") #other agglomeration methods are "ward.D", "ward.D2", "single", "complete", "average", "mcquitty", "median", or "centroid"
dend <- as.dendrogram(clusters) 

p1<-dend %>% 
  dendextend::set("branches_k_color", k = 6) %>% 
  dendextend::set("hang_leaves", c(0.05)) %>% 
  dendextend::set("labels_cex", c(0.5)) %>%
  dendextend::set("labels_colors", k = 6) %>% 
  dendextend::set("branches_lwd", c(0.7)) %>% 
  
  as.ggdend %>%
  ggplot (offset_labels = -0.2) +
  theme_dendro() +
  ylim(0, max(get_branches_heights(dend))) +
  labs(title = "S. papillosus: Hierarchical Cluster Dendrogram",
       subtitle = "filtered, TMM normalized",
       y = "Distance",
       x = "Life stage") +
  coord_fixed(1/2) +
  theme(axis.title.x = element_text(color = "black"),
        axis.title.y = element_text(angle = 90),
        axis.text.y = element_text(angle = 0),
        axis.line.y = element_line(color = "black"),
        axis.ticks.y = element_line(color = "black"),
        axis.ticks.length.y = unit(2, "mm"))

Dendrogram to visualize heirachical clustering

Clustering performed on filtered and normalized abundance data using the “complete” method.

# Principal component analysis (PCA) -------------
# this also works on a data matrix, not a data frame
pca.res <- prcomp(t(log2.cpm.filtered.norm), scale.=F, retx=T)
#summary(pca.res) # Prints variance summary for all principal components.

#pca.res$rotation #$rotation shows you how much each gene influenced each PC (called 'scores')
#pca.res$x # 'x' shows you how much each sample influenced each PC (called 'loadings')
#note that these have a magnitude and a direction (this is the basis for making a PCA plot)
## This generates a screeplot: a standard way to view eigenvalues for each PCA. Shows the proportion of variance accounted for by each PC. Plotting only the first 10 dimensions.
p2<-fviz_eig(pca.res,
             barcolor = brewer.pal(8,"Pastel2")[8],
             barfill = brewer.pal(8,"Pastel2")[8],
             linecolor = "black",
             main = "S. papillosus Scree plot: proportion of variance accounted for by each principal component",
             ggtheme = theme_bw()) 
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     

Screeplot of PCA Eigenvalues

A scree plot is a standard way to view eigenvalues for each PCA. The plot shows the proportion of variance accounted for by each PC.

pc.var<-pca.res$sdev^2 # sdev^2 captures these eigenvalues from the PCA result
pc.per<-round(pc.var/sum(pc.var)*100, 1) # we can then use these eigenvalues to calculate the percentage variance explained by each PC

# Visualize the PCA result ------------------
#lets first plot any two PCs against each other
#We know how much each sample contributes to each PC (loadings), so let's plot
pca.res.df <- as_tibble(pca.res$x)

# Plotting PC1 and PC2
p3<-ggplot(pca.res.df) +
  aes(x=PC1, y=PC2, label=targets$group, 
      fill = targets$group,
      color = targets$group
  ) +
  geom_point(size=4, shape= 21, color = "black", alpha = 0.5) +
  #geom_label(color = "black", size = 2) +
  #scale_fill_brewer(palette = "Set2") +
  #scale_color_brewer(palette = "Set2", guide = FALSE) +
  #stat_ellipse() +
  xlab(paste0("PC1 (",pc.per[1],"%",")")) + 
  ylab(paste0("PC2 (",pc.per[2],"%",")")) +
  labs(title="S. papillosus: Principal Components Analysis of RNAseq Samples",
       caption = "Note: analysis is blind to life stage identity.",
       subtitle ="All samples/groups",
       fill = "Life Stage") +
  scale_x_continuous(expand = c(.3, .3)) +
  scale_y_continuous(expand = c(.3, .3)) +
  coord_fixed() +
  theme_bw()

PCA Plot

Plot of the samples in PCA space. Fill color indicates life stage.

# Create a PCA 'small multiples' chart ----
pca.res.df <- pca.res$x[,1:3] %>% 
  as_tibble() %>%
  add_column(sample = targets$sample,
             group = targets$group)

pca.pivot <- pivot_longer(pca.res.df, # dataframe to be pivoted
                          cols = PC1:PC3, # column names to be stored as a SINGLE variable
                          names_to = "PC", # name of that new variable (column)
                          values_to = "loadings") # name of new variable (column) storing all the values (data)
PC1<-subset(pca.pivot, PC == "PC1")
PC2 <-subset(pca.pivot, PC == "PC2")
#PC3 <- subset(pca.pivot, PC == "PC3")
#PC4 <- subset(pca.pivot, PC == "PC4")

p6<-ggplot(pca.pivot) +
  aes(x=sample, y=loadings) + # you could iteratively 'paint' different covariates onto this plot using the 'fill' aes
  geom_bar(stat="identity", fill = brewer.pal(8,"Pastel2")[8]) +
  scale_fill_brewer(palette = "Set2") +
  facet_wrap(~PC) +
  geom_bar(data = PC1, stat = "identity", aes(fill = group)) +
  geom_bar(data = PC2, stat = "identity", aes(fill = group)) +
  labs(title="S. papillosus: PCA 'small multiples' plot",
       fill = "Life Stage/Source",
       subtitle ="All samples/groups") +
  scale_x_discrete(limits = targets$sample, labels = targets$group) +
  theme_bw() +
  coord_flip()

PCA “Small Multiples” Plot

Heatmap of Gene Expression Across Life Stages

Make a heatmap for all the genes using the Log2CPM values.

suppressPackageStartupMessages({
library(pheatmap)
library(RColorBrewer)
library(heatmaply)
})
# Make a heatmap for all the genes using the Log2CPM values

diffGenes <- v.DEGList.filtered.norm$E %>%
  as_tibble(rownames = "geneID", .name_repair = "unique") %>%
  dplyr::select(!geneID) %>%
  as.matrix()
rownames(diffGenes) <- rownames(v.DEGList.filtered.norm$E)
colnames(diffGenes) <- as.character(v.DEGList.filtered.norm$targets$group)
clustColumns <- hclust(as.dist(1-cor(diffGenes, method="spearman")), method="complete")
clustRows <- hclust(as.dist(1-cor(t(diffGenes), 
                                  method="pearson")), 
                    method="complete") 
par(cex.main=1.2)

showticklabels <- c(TRUE,FALSE)
p<-pheatmap(diffGenes,
            color = RdBu(75),
            cluster_rows = clustRows,
            cluster_cols = clustColumns,
            show_rownames = F,
            scale = "row",
            angle_col = 45,
            main = "S. papillosus: Log2 Counts Per Million (CPM) Expression Across Life Stages"
          
)

Differentially Expressed Genes

This chunk uses a variance-stabilized DGEList of filtered and normalized abundance data. These data/results are examples, a responsive version of this code is avaliable in a Shiny App.

# Introduction to this chunk ----
# Because we have access to biological and technical replicates, we can use statistical tools for differential expression analysis
# Useful reading on differential expression: https://ucdavis-bioinformatics-training.github.io/2018-June-RNA-Seq-Workshop/thursday/DE.html

# Load packages ----
suppressPackageStartupMessages({
  library(tidyverse)
  library(limma) # differential gene expression using linear modeling
  library(edgeR)
  library(gt) 
  library(DT) 
  library(plotly)
  library(ggthemes)
  library(RColorBrewer)
  source("../Strongyloides_RNAseq_Browser/Server/theme_Publication.R")
})

diffGenes.df <- v.DEGList.filtered.norm$E %>%
  as_tibble(rownames = "geneID", .name_repair = "unique")

# Set Expression threshold values for plotting and saving DEGs ----
adj.P.thresh <- 0.05
lfc.thresh <- 1 

group <- factor(v.DEGList.filtered.norm$targets$group)
design <- model.matrix(~0 + group) # no intercept/blocking for matrix, comparisons across group
colnames(design) <- levels(group)


# Fit a linear model to the data ----
fit <- lmFit(v.DEGList.filtered.norm, design = design)

# As an example, generate comparison matrix for a pairwise comparison ----
# iL3s vs FLF
# Note that the target/contrast goups will be divided by the number of life 
# stage groups e.g. PF+FLF/2 - iL3+iL3a+pfL1+ppL1+ppL3/5
comparison <- c('(iL3)-(FLF)')

targetStage<- comparison %>%
  str_split(pattern="-", simplify = T) %>%
  .[,1] %>%
  gsub("(", "", ., fixed = TRUE) %>%
  gsub(")", "", ., fixed = TRUE) %>%
  str_split(pattern = "\\+", simplify = T)

contrastStage<-comparison %>%
  str_split(pattern="-", simplify = T) %>%
  .[,2] %>%
  gsub("(", "", ., fixed = TRUE) %>%
  gsub(")", "", ., fixed = TRUE)  %>%
  str_split(pattern = "\\+", simplify = T)

comparison<- sapply(seq_along(comparison),function(x){
  tS <- as.vector(targetStage[x,]) %>%
    .[. != ""] 
  cS <- as.vector(contrastStage[x,]) %>%
    .[. != ""] 
  paste(paste0(tS, 
               collapse = "+") %>%
          paste0("(",.,")/",length(tS)),
        paste0(cS, 
               collapse = "+") %>%
          paste0("(",.,")/",length(cS)),
        sep = "-")
  
})

# Generate contrast matrix ----
contrast.matrix <- makeContrasts(contrasts = comparison,
                                 levels=design)

# extract the linear model fit -----
fits <- contrasts.fit(fit, contrast.matrix)
# empirical bayes smoothing of gene-wise standard deviations provides increased power (see: https://www.degruyter.com/doi/10.2202/1544-6115.1027)
ebFit <- eBayes(fits)

# Pull out the DEGs that pass a specific threshold for all pairwise comparisons ----
# Adjust for multiple comparisons using method = global. 
results <- decideTests(ebFit, method="global", adjust.method="BH", p.value = adj.P.thresh)

recode01<- function(x){
  case_when(x == 1 ~ "Up",
            x == -1 ~ "Down",
            x == 0 ~ "NotSig")
}
diffDesc <- results %>%
  as_tibble(rownames = "geneID") %>%
  dplyr::mutate(across(-geneID, unclass)) %>%
  dplyr::mutate(across(where(is.double), recode01))

# Function that identifies top DEGs between a specific contrast ----
calc_DEG_tbl <- function (ebFit, coef) {
  myTopHits.df <- limma::topTable(ebFit, adjust ="BH", 
                                  coef=coef, number=40000, 
                                  sort.by="logFC") %>%
    as_tibble(rownames = "geneID") %>%
    dplyr::rename(tStatistic = t, LogOdds = B, BH.adj.P.Val = adj.P.Val) %>%
    dplyr::relocate(UniProtKB, Description, InterPro, GO_term, 
                    In.subclade_geneID, In.subclade_percent_homology,
                    Out.subclade_geneID, Out.subclade_percent_homology,
                    Ce_geneID, Ce_percent_homology, .after = LogOdds)
  
  myTopHits.df
}

list.myTopHits.df <- sapply(comparison, function(y){
  calc_DEG_tbl(ebFit, y)}, 
  simplify = FALSE, 
  USE.NAMES = TRUE)

list.myTopHits.df <- sapply(comparison, function(y){
  list.myTopHits.df[[y]] %>%
    dplyr::select(geneID, 
                  logFC, 
                  BH.adj.P.Val:Ce_percent_homology)},
  simplify = FALSE, 
  USE.NAMES = TRUE)

# Get log2CPM values and threshold information for genes of interest
list.myTopHits.df <- sapply(seq_along(comparison), function(y){
  tS<- targetStage[y,][targetStage[y,]!=""]
  cS<- contrastStage[y,][contrastStage[y,]!=""]
  
  concat_name <- function(x) {
    ifelse(x == "target", 
           paste(tS, collapse = "+"), 
           paste(cS, collapse = "+"))
  }
  
  groupAvgs <- diffGenes.df %>%
    dplyr::select(geneID, starts_with(paste0(tS,"-")), 
                  starts_with(paste0(cS,"-"))) %>%
    pivot_longer(cols = -geneID, names_to = c("group","sample"), values_to = "CPM",
                 names_sep = "-") %>%
    dplyr::mutate(contrastID = if_else(group %in% tS,"target", "contrast")) %>%
    group_by(geneID, contrastID) %>%
    dplyr::select(-sample) %>%
    summarize(mean = mean(CPM), .groups = "drop_last") %>%
    pivot_wider(names_from = contrastID, values_from = mean) %>%
    dplyr::relocate(contrast, .after = target) %>%
    dplyr::rename_with(concat_name, -geneID) %>%
    dplyr::rename_with(.cols =-geneID, .fn = ~ paste0("avg_(",.x,")"))
  
  diffGenes.df %>%
    dplyr::select(geneID, starts_with(paste0(tS,"-")), 
                  starts_with(paste0(cS,"-"))) %>%
    left_join(groupAvgs, by = "geneID") %>%
    left_join(list.myTopHits.df[[y]],., by = "geneID") %>%
    left_join(dplyr::select(diffDesc,geneID,comparison[y]), by = "geneID") %>%
    dplyr::rename(DEG_Desc=comparison[y]) %>%
    dplyr::relocate(DEG_Desc) %>%
    dplyr::relocate(logFC:Ce_percent_homology, .after = last_col())
  
},
simplify = FALSE)

comparison <- gsub("/[0-9]*","", comparison)
names(list.myTopHits.df) <- comparison

list.myTopHits.df <- sapply(comparison, function(y){
  list.myTopHits.df[[y]] %>%
    dplyr::mutate(DEG_Desc = case_when(DEG_Desc == "Up" ~ paste0("Up in ", str_split(y,'-',simplify = T)[1,1]),
                                       DEG_Desc == "Down" ~ paste0("Down in ", str_split(y,'-',simplify = T)[1,1]),
                                       DEG_Desc == "NotSig" ~ "NotSig")) 
},
simplify = FALSE, 
USE.NAMES = TRUE)

# PC1 Volcano Plot and Interactive Table ----
vplot1 <- ggplot(list.myTopHits.df[[1]]) +
  aes(y=-log10(BH.adj.P.Val), x=logFC, text = paste(geneID, "<br>",
                                                    "logFC:", round(logFC, digits = 2), "<br>",
                                                    "p-val:", format(BH.adj.P.Val, digits = 3, scientific = TRUE))) +
  geom_point(size=2) +
  geom_hline(yintercept = -log10(adj.P.thresh), 
             linetype="longdash", 
             colour="grey", 
             size=1) + 
  geom_vline(xintercept = lfc.thresh, 
             linetype="longdash", 
             colour="#BE684D", 
             size=1) +
  geom_vline(xintercept = -lfc.thresh, 
             linetype="longdash", 
             colour="#2C467A", 
             size=1) +
  labs(title = paste0('S. papillosus, Pairwise Comparison: ',
                      gsub('-',
                           ' vs ',
                           comparison[1])),
       subtitle = paste0("grey line: p = ",
                         adj.P.thresh, "; colored lines: log-fold change = ", lfc.thresh),
       color = "GeneIDs") +
  theme_Publication() 
vplot1


# Interactive Tables
yy<- 1
tS<- targetStage[yy,][targetStage[yy,]!=""]
cS<- contrastStage[yy,][contrastStage[yy,]!=""]
sample.num.tS <- sapply(tS, function(x) {colSums(v.DEGList.filtered.norm$design)[[x]]}) %>% sum()
sample.num.cS <- sapply(cS, function(x) {colSums(v.DEGList.filtered.norm$design)[[x]]}) %>% sum()


n_num_cols <- sample.num.tS + sample.num.cS + 5
index_homologs <- length(colnames(list.myTopHits.df[[yy]])) - 5


LS.datatable <- list.myTopHits.df[[yy]] %>%
  DT::datatable(rownames = FALSE,
                caption = htmltools::tags$caption(
                  style = 'caption-side: top; text-align: left; color: black',
                  htmltools::tags$b('Differentially Expressed Genes in', 
                                    htmltools::tags$em('S. papillosus'), 
                                    gsub('-',' vs ',comparison[yy])),
                  htmltools::tags$br(),
                  "Threshold: p < ",
                  adj.P.thresh, "; log-fold change > ",
                  lfc.thresh,
                  htmltools::tags$br(),
                  'Values = log2 counts per million'),
                options = list(autoWidth = TRUE,
                               scrollX = TRUE,
                               scrollY = '300px',
                               scrollCollapse = TRUE,
                               order = list(n_num_cols-1, 
                                            'desc'),
                               searchHighlight = TRUE, 
                               pageLength = 25, 
                               lengthMenu = c("5",
                                              "10",
                                              "25",
                                              "50",
                                              "100"),
                               columnDefs = list(
                                 list(
                                   targets = ((n_num_cols + 
                                                 1)),
                                   render = JS(
                                     "function(data, row) {",
                                     "data.toExponential(1);",
                                     "}")
                                 ),
                                 list(
                                   targets = ((n_num_cols + 
                                                 4):(n_num_cols + 
                                                       5)),
                                   render = JS(
                                     "function(data, type, row, meta) {",
                                     "return type === 'display' && data.length > 20 ?",
                                     "'<span title=\"' + data + '\">' + data.substr(0, 20) + '...</span>' : data;",
                                     "}")
                                 ),
                                 list(targets = "_all",
                                      class="dt-right")
                               ),
                               rowCallback = JS(c(
                                 "function(row, data){",
                                 "  for(var i=0; i<data.length; i++){",
                                 "    if(data[i] === null){",
                                 "      $('td:eq('+i+')', row).html('NA')",
                                 "        .css({'color': 'rgb(151,151,151)', 'font-style': 'italic'});",
                                 "    }",
                                 "  }",
                                 "}"  
                               ))
                               
                )) 
LS.datatable <- LS.datatable %>%
  DT::formatRound(columns=c(3:n_num_cols), 
                  digits=3)

LS.datatable <- LS.datatable %>%
  DT::formatRound(columns=c(n_num_cols+2, 
                            index_homologs+1,
                            index_homologs+3), 
                  digits=2)

LS.datatable <- LS.datatable %>%
  DT::formatSignif(columns=c(n_num_cols+1), 
                   digits=3)

LS.datatable

NA

Benchmarking

Tables with data suitable for benchmarking are not currently available.

Functional Enrichment Analysis

This code prerform GSEA using the clusterProfiler library. Ability to do this depends on the availability of gene sets. Major databases (e.g. msigdb don’t seem to have Strongyloides information. They do have C. elegans gene sets, but I’m not convinced the homology information is good enough for the comparison to be unbiased/meaningful. In Hunt et al 2016, there is an Ensembl Compara protein family set; we will use this as the basis for our gene set libraries.
Note that this uses specific transcript information, which I throw out (e.g. SSTP_0001137400.2 is recoded as SSTP_0001137400).

Given a priori defined set of gene S (e.g., genes shareing the same DO category), the goal of GSEA is to determine whether the members of S are randomly distributed throughout the ranked gene list (L) or primarily found at the top or bottom.
There are three key elements of the GSEA method:
Calculation of an Enrichment Score.
The enrichment score (ES) represent the degree to which a set S is over-represented at the top or bottom of the ranked list L. The score is calculated by walking down the list L, increasing a running-sum statistic when we encounter a gene in S and decreasing when it is not. The magnitude of the increment depends on the gene statistics (e.g., correlation of the gene with phenotype). The ES is the maximum deviation from zero encountered in the random walk; it corresponds to a weighted Kolmogorov-Smirnov-like statistic (Subramanian et al. 2005).
Esimation of Significance Level of ES.
The p-value of the ES is calculated using permutation test. Specifically, we permute the gene labels of the gene list L and recompute the ES of the gene set for the permutated data, which generate a null distribution for the ES. The p-value of the observed ES is then calculated relative to this null distribution.
Adjustment for Multiple Hypothesis Testing.
When the entire gene sets were evaluated, DOSE adjust the estimated significance level to account for multiple hypothesis testing and also q-values were calculated for FDR control.

Appendix I: All code for this report

LS0tCnRpdGxlOiBPZmZsaW5lIERhdGEgQW5hbHlzaXMgb2YgU3Ryb25neWxvaWRlcyB2ZW5lenVlbGVuc2lzIGJ1bGsgUk5Bc2VxIGRhdGEKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKLS0tCgojIEludHJvZHVjdGlvbgpUaGUgZ29hbCBvZiB0aGlzIGZpbGUgaXMgdG8gbGF5IG91dCBwcm9vZi1vZi1jb25jZXB0IGFuYWx5c2VzIG9mIHRoZSAqU3Ryb25neWxvaWRlcyBwYXBpbGxvc3VzKiBSTkFzZXEgZGF0YXNldCBvcmlnaW5hbGx5IGFuYWx5emVkIGJ5IFtIdW50ICpldCBhbCogMjAxNl0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9uZy4zNDk1KS4gIAoKVGhpcyBkYXRhc2V0IGluY2x1ZGVzIHNhbXBsZXMgcmVwcmVzZW50aW5nIDUgbGlmZSBzdGFnZXMsIGVhY2ggd2l0aCAyIGJpb2xvZ2ljYWwgcmVwbGljYXRlczogTDEvTDJzLCBGTEYsIEZMTSwgaUwzLCBQRi4gIAoKIyMjIERhdGEgUHJlLVByb2Nlc3NpbmcgICAgCkEgZnVsbCBkZXNjcmlwdGlvbiBvZiBLYWxsaXN0byBhbGlnbm1lbnQgYW5kIGRhdGEgZmlsdGVyaW5nL25vcm1hbGl6YXRpb24gc3RlcHMgY2FuIGJlIGZvdW5kIGluIGBTcF9STkFzZXFfRGF0YV9Qcm9jZXNzaW5nLnJtZGAuCgojIyMgRGF0YSBBbmFseXNpcyAgIApUaGUgbGltbWEgcGFja2FnZSAoIFtSaXRjaGllICpldCBhbCogMjAxNV0oaHR0cHM6Ly9wdWJtZWQubmNiaS5ubG0ubmloLmdvdi8yNTYwNTc5Mi8pLCBbUGhpcHNvbiAqZXQgYWwqIDIwMTZdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzUzNzM4MTIvKSkgaXMgdXNlZCB0byBjb25kdWN0IHBhaXJ3aXNlIGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24gYW5hbHlzZXMgYmV0d2VlbiBsaWZlIHN0YWdlcy4gVGhlIHJlc3VsdHMgb2YgdGhlIHBhaXJ3aXNlIGNvbXBhcmlzb24gaXMgZGlzcGxheWVkIGFzIGEgdm9sY2FubyBwbG90IGFuZCBpbnRlcmFjdGl2ZSBEYXRhVGFibGUuIAoKIyBDb2RlCkFsbCBjb2RlIGlzIGVjaG9lZCB1bmRlciBkZXNjcmlwdGl2ZSBoZWFkZXJzOyBjb2RlIGNodW5rcyBhcmUgaGlkZGVuIGZyb20gdmlldyBieSBkZWZhdWx0LiBVc2VycyBtYXkgc2hvdyBoaWRkZW4gUiBjb2RlIGJ5IGNsaWNraW5nIHRoZSBTaG93IGJ1dHRvbnMuIEluIGFkZGl0aW9uLCBhbGwgY29kZSBjaHVua3MgYXJlIGNvbGxhdGVkIGF0IHRoZSBlbmQgb2YgdGhlIGRvY3VtZW50IGluIGFuIEFwcGVuZGl4LiAgCgojIyBMb2FkIGFuZCBQYXJzZSBQcmVwcm9jZXNzZWQgRGF0YQpUaGlzIGNvZGUgbG9hZHMgUiBkYXRhIG9iamVjdHMgdGhhdCBoYXMgYmVlbiBwcmVwcm9wcm9jZXNzZWQgYnkgYFNwX1JOQXNlcV9EYXRhX1Byb2Nlc3Npbmcucm1kYC4gIApgYGB7ciBsb2FkQmFzZURhdGF9CiMgTG9hZCBhbmQgUGFyc2UgUHJlcHJvY2Vzc2VkIERhdGEKbG9hZCAoZmlsZSA9ICIuLi9PdXRwdXRzL1NwUk5Bc2VxX2RhdGFfcHJlcHJvY2Vzc2VkIikKdGFyZ2V0cyA8LSBTcFJOQXNlcS5wcmVwcm9jZXNzZWQuZGF0YSR0YXJnZXRzCmFubm90YXRpb25zIDwtIFNwUk5Bc2VxLnByZXByb2Nlc3NlZC5kYXRhJGFubm90YXRpb25zCmxvZzIuY3BtLmZpbHRlcmVkLm5vcm0gPC0gU3BSTkFzZXEucHJlcHJvY2Vzc2VkLmRhdGEkbG9nMi5jcG0uZmlsdGVyZWQubm9ybQpteURHRUxpc3QuZmlsdGVyZWQubm9ybSA8LVNwUk5Bc2VxLnByZXByb2Nlc3NlZC5kYXRhJG15REdFTGlzdC5maWx0ZXJlZC5ub3JtCgpybShTcFJOQXNlcS5wcmVwcm9jZXNzZWQuZGF0YSkKCmxvYWQoZmlsZSA9ICIuLi9TdHJvbmd5bG9pZGVzX1JOQXNlcV9Ccm93c2VyL0RhdGEvU3BfdkRFR0xpc3QiKQoKYGBgCgoKIyMgSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgYW5kIFByaW5jaXBsZSBDb21wb25lbnRzIEFuYWx5c2lzICAKVGhpcyBjb2RlIGNodW5rIHN0YXJ0cyB3aXRoIGZpbHRlcmVkIGFuZCBub3JtYWxpemVkIGFidW5kYW5jZSBkYXRhIGluIGEgZGF0YSBmcmFtZSAobm90IHRpZHkpLiBJdCB3aWxsIGltcGxlbWVudCBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyBhbmQgUENBIGFuYWx5c2VzIG9uIHRoZSBkYXRhLiBJdCB3aWxsIHBsb3QgdmFyaW91cyBncmFwaHMsIGluY2x1ZGluZyBhIGRlbmRyb2dyYW0gb2YgdGhlIGhlaXJhY2hpY2FsIGNsdXN0ZXJpbmcsIGFuZCBzZXZlcmFsIHBsb3RzIG9mIHZpc3VhbGl6ZSB0aGUgUENBLiBCZWNhdXNlIHRoZSBkYXRhIHRoYXQgYXJlIHBhc3NlZCBpbnRvIHRoZXNlIGFuYWx5c2VzIGRvIG5vdCBoYXZlIGJhdGNoIGNvcnJlY3Rpb24gYXBwbGllZCwgdGhlIGNsdXN0ZXJpbmcgYXBwZWFycyBkb21pbmFudGVkIGJ5IGEgYmF0Y2ggZWZmZWN0LiAgIApgYGB7ciBtdWx0aXZhcmlhdGUuMX0KIyBJbnRyb2R1Y3Rpb24gdG8gdGhpcyBjaHVuayAtLS0tLS0tLS0tLQojIFRoaXMgY29kZSBjaHVuayBzdGFydHMgd2l0aCBmaWx0ZXJlZCBhbmQgbm9ybWFsaXplZCBhYnVuZGFuY2UgZGF0YSBpbiBhIGRhdGEgZnJhbWUgKG5vdCB0aWR5KS4KIyBJdCB3aWxsIGltcGxlbWVudCBoaWVyYXJjaGljYWwgY2x1c3RlcmluZyBhbmQgUENBIGFuYWx5c2VzIG9uIHRoZSBkYXRhLgojIEl0IHdpbGwgcGxvdCB2YXJpb3VzIGdyYXBocyBhbmQgY2FuIHNhdmUgdGhlbSBpbiBQREYgZmlsZXMuCiMgTG9hZCBwYWNrYWdlcyAtLS0tLS0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KHRpZHl2ZXJzZSkgIyB5b3UncmUgZmFtaWxpYXIgd2l0aCB0aGlzIGZyb210IHRoZSBwYXN0IHR3byBsZWN0dXJlcwogIGxpYnJhcnkoZ2dwbG90MikKICBsaWJyYXJ5KFJDb2xvckJyZXdlcikKICBsaWJyYXJ5KGdnZGVuZHJvKQogIGxpYnJhcnkobWFncml0dHIpCiAgbGlicmFyeShmYWN0b2V4dHJhKQogIGxpYnJhcnkoZ3JpZEV4dHJhKQogIGxpYnJhcnkoY293cGxvdCkKICBsaWJyYXJ5KGRlbmRleHRlbmQpCn0pCgojIElkZW50aWZ5IHZhcmlhYmxlcyBvZiBpbnRlcmVzdCBpbiBzdHVkeSBkZXNpZ24gZmlsZSAtLS0tCmdyb3VwIDwtIGZhY3Rvcih0YXJnZXRzJGdyb3VwKQoKIyBIaWVyYXJjaGljYWwgY2x1c3RlcmluZyAtLS0tLS0tLS0tLS0tLS0KIyBSZW1lbWJlcjogaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcgY2FuIG9ubHkgd29yayBvbiBhIGRhdGEgbWF0cml4LCBub3QgYSBkYXRhIGZyYW1lCgojIENhbGN1bGF0ZSBkaXN0YW5jZSBtYXRyaXgKIyBkaXN0IGNhbGN1bGF0ZXMgZGlzdGFuY2UgYmV0d2VlbiByb3dzLCBzbyB0cmFuc3Bvc2UgZGF0YSBzbyB0aGF0IHdlIGdldCBkaXN0YW5jZSBiZXR3ZWVuIHNhbXBsZXMuCiMgaG93IHNpbWlsYXIgYXJlIHNhbXBsZXMgZnJvbSBlYWNoIG90aGVyCmNvbG5hbWVzKGxvZzIuY3BtLmZpbHRlcmVkLm5vcm0pPC1wYXN0ZSh0YXJnZXRzJGdyb3VwLHN1YnN0cih0YXJnZXRzJHNhbXBsZSwgOSwxMCksIHNlcCA9ICIuIikKZGlzdGFuY2UgPC0gZGlzdCh0KGxvZzIuY3BtLmZpbHRlcmVkLm5vcm0pLCBtZXRob2QgPSAibWF4aW11bSIpICNvdGhlciBkaXN0YW5jZSBtZXRob2RzIGFyZSAiZXVjbGlkZWFuIiwgbWF4aW11bSIsICJtYW5oYXR0YW4iLCAiY2FuYmVycmEiLCAiYmluYXJ5IiBvciAibWlua293c2tpIgoKIyBDYWxjdWxhdGUgY2x1c3RlcnMgdG8gdmlzdWFsaXplIGRpZmZlcmVuY2VzLiBUaGlzIGlzIHRoZSBoaWVyYXJjaGljYWwgY2x1c3RlcmluZy4KIyBUaGUgbWV0aG9kcyBoZXJlIGluY2x1ZGU6IHNpbmdsZSAoaS5lLiAiZnJpZW5kcy1vZi1mcmllbmRzIiksIGNvbXBsZXRlIChpLmUuIGNvbXBsZXRlIGxpbmthZ2UpLCBhbmQgYXZlcmFnZSAoaS5lLiBVUEdNQSkuIEhlcmUncyBhIGNvbXBhcmlzb24gb2YgZGlmZmVyZW50IHR5cGVzOiBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9VUEdNQSNDb21wYXJpc29uX3dpdGhfb3RoZXJfbGlua2FnZXMKY2x1c3RlcnMgPC0gaGNsdXN0KGRpc3RhbmNlLCBtZXRob2QgPSAiY29tcGxldGUiKSAjb3RoZXIgYWdnbG9tZXJhdGlvbiBtZXRob2RzIGFyZSAid2FyZC5EIiwgIndhcmQuRDIiLCAic2luZ2xlIiwgImNvbXBsZXRlIiwgImF2ZXJhZ2UiLCAibWNxdWl0dHkiLCAibWVkaWFuIiwgb3IgImNlbnRyb2lkIgpkZW5kIDwtIGFzLmRlbmRyb2dyYW0oY2x1c3RlcnMpIAoKcDE8LWRlbmQgJT4lIAogIGRlbmRleHRlbmQ6OnNldCgiYnJhbmNoZXNfa19jb2xvciIsIGsgPSA2KSAlPiUgCiAgZGVuZGV4dGVuZDo6c2V0KCJoYW5nX2xlYXZlcyIsIGMoMC4wNSkpICU+JSAKICBkZW5kZXh0ZW5kOjpzZXQoImxhYmVsc19jZXgiLCBjKDAuNSkpICU+JQogIGRlbmRleHRlbmQ6OnNldCgibGFiZWxzX2NvbG9ycyIsIGsgPSA2KSAlPiUgCiAgZGVuZGV4dGVuZDo6c2V0KCJicmFuY2hlc19sd2QiLCBjKDAuNykpICU+JSAKICAKICBhcy5nZ2RlbmQgJT4lCiAgZ2dwbG90IChvZmZzZXRfbGFiZWxzID0gLTAuMikgKwogIHRoZW1lX2RlbmRybygpICsKICB5bGltKDAsIG1heChnZXRfYnJhbmNoZXNfaGVpZ2h0cyhkZW5kKSkpICsKICBsYWJzKHRpdGxlID0gIlMuIHBhcGlsbG9zdXM6IEhpZXJhcmNoaWNhbCBDbHVzdGVyIERlbmRyb2dyYW0iLAogICAgICAgc3VidGl0bGUgPSAiZmlsdGVyZWQsIFRNTSBub3JtYWxpemVkIiwKICAgICAgIHkgPSAiRGlzdGFuY2UiLAogICAgICAgeCA9ICJMaWZlIHN0YWdlIikgKwogIGNvb3JkX2ZpeGVkKDEvMikgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDApLAogICAgICAgIGF4aXMubGluZS55ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50aWNrcy5sZW5ndGgueSA9IHVuaXQoMiwgIm1tIikpCmBgYAoKIyMjIERlbmRyb2dyYW0gdG8gdmlzdWFsaXplIGhlaXJhY2hpY2FsIGNsdXN0ZXJpbmcgIApDbHVzdGVyaW5nIHBlcmZvcm1lZCBvbiBmaWx0ZXJlZCBhbmQgbm9ybWFsaXplZCBhYnVuZGFuY2UgZGF0YSB1c2luZyB0aGUgImNvbXBsZXRlIiBtZXRob2QuICAKYGBge3IgZWNobyA9IEZBTFNFfQpwMQpgYGAKCmBgYHtyIG11bHRpdmFyaWF0ZS4yfQojIFByaW5jaXBhbCBjb21wb25lbnQgYW5hbHlzaXMgKFBDQSkgLS0tLS0tLS0tLS0tLQojIHRoaXMgYWxzbyB3b3JrcyBvbiBhIGRhdGEgbWF0cml4LCBub3QgYSBkYXRhIGZyYW1lCnBjYS5yZXMgPC0gcHJjb21wKHQobG9nMi5jcG0uZmlsdGVyZWQubm9ybSksIHNjYWxlLj1GLCByZXR4PVQpCiNzdW1tYXJ5KHBjYS5yZXMpICMgUHJpbnRzIHZhcmlhbmNlIHN1bW1hcnkgZm9yIGFsbCBwcmluY2lwYWwgY29tcG9uZW50cy4KCiNwY2EucmVzJHJvdGF0aW9uICMkcm90YXRpb24gc2hvd3MgeW91IGhvdyBtdWNoIGVhY2ggZ2VuZSBpbmZsdWVuY2VkIGVhY2ggUEMgKGNhbGxlZCAnc2NvcmVzJykKI3BjYS5yZXMkeCAjICd4JyBzaG93cyB5b3UgaG93IG11Y2ggZWFjaCBzYW1wbGUgaW5mbHVlbmNlZCBlYWNoIFBDIChjYWxsZWQgJ2xvYWRpbmdzJykKI25vdGUgdGhhdCB0aGVzZSBoYXZlIGEgbWFnbml0dWRlIGFuZCBhIGRpcmVjdGlvbiAodGhpcyBpcyB0aGUgYmFzaXMgZm9yIG1ha2luZyBhIFBDQSBwbG90KQojIyBUaGlzIGdlbmVyYXRlcyBhIHNjcmVlcGxvdDogYSBzdGFuZGFyZCB3YXkgdG8gdmlldyBlaWdlbnZhbHVlcyBmb3IgZWFjaCBQQ0EuIFNob3dzIHRoZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGFjY291bnRlZCBmb3IgYnkgZWFjaCBQQy4gUGxvdHRpbmcgb25seSB0aGUgZmlyc3QgMTAgZGltZW5zaW9ucy4KcDI8LWZ2aXpfZWlnKHBjYS5yZXMsCiAgICAgICAgICAgICBiYXJjb2xvciA9IGJyZXdlci5wYWwoOCwiUGFzdGVsMiIpWzhdLAogICAgICAgICAgICAgYmFyZmlsbCA9IGJyZXdlci5wYWwoOCwiUGFzdGVsMiIpWzhdLAogICAgICAgICAgICAgbGluZWNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgIG1haW4gPSAiUy4gcGFwaWxsb3N1cyBTY3JlZSBwbG90OiBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGFjY291bnRlZCBmb3IgYnkgZWFjaCBwcmluY2lwYWwgY29tcG9uZW50IiwKICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9idygpKSAKYGBgCgojIyMgU2NyZWVwbG90IG9mIFBDQSBFaWdlbnZhbHVlcyAgCkEgc2NyZWUgcGxvdCBpcyBhIHN0YW5kYXJkIHdheSB0byB2aWV3IGVpZ2VudmFsdWVzIGZvciBlYWNoIFBDQS4gVGhlIHBsb3Qgc2hvd3MgdGhlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgYWNjb3VudGVkIGZvciBieSBlYWNoIFBDLiAKYGBge3IgZWNobyA9IEZBTFNFfQpwMgpgYGAKCmBgYHtyIG11bHRpdmFyaWF0ZS4zfQpwYy52YXI8LXBjYS5yZXMkc2Rldl4yICMgc2Rldl4yIGNhcHR1cmVzIHRoZXNlIGVpZ2VudmFsdWVzIGZyb20gdGhlIFBDQSByZXN1bHQKcGMucGVyPC1yb3VuZChwYy52YXIvc3VtKHBjLnZhcikqMTAwLCAxKSAjIHdlIGNhbiB0aGVuIHVzZSB0aGVzZSBlaWdlbnZhbHVlcyB0byBjYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2UgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IGVhY2ggUEMKCiMgVmlzdWFsaXplIHRoZSBQQ0EgcmVzdWx0IC0tLS0tLS0tLS0tLS0tLS0tLQojbGV0cyBmaXJzdCBwbG90IGFueSB0d28gUENzIGFnYWluc3QgZWFjaCBvdGhlcgojV2Uga25vdyBob3cgbXVjaCBlYWNoIHNhbXBsZSBjb250cmlidXRlcyB0byBlYWNoIFBDIChsb2FkaW5ncyksIHNvIGxldCdzIHBsb3QKcGNhLnJlcy5kZiA8LSBhc190aWJibGUocGNhLnJlcyR4KQoKIyBQbG90dGluZyBQQzEgYW5kIFBDMgpwMzwtZ2dwbG90KHBjYS5yZXMuZGYpICsKICBhZXMoeD1QQzEsIHk9UEMyLCBsYWJlbD10YXJnZXRzJGdyb3VwLCAKICAgICAgZmlsbCA9IHRhcmdldHMkZ3JvdXAsCiAgICAgIGNvbG9yID0gdGFyZ2V0cyRncm91cAogICkgKwogIGdlb21fcG9pbnQoc2l6ZT00LCBzaGFwZT0gMjEsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjUpICsKICAjZ2VvbV9sYWJlbChjb2xvciA9ICJibGFjayIsIHNpemUgPSAyKSArCiAgI3NjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsKICAjc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIsIGd1aWRlID0gRkFMU0UpICsKICAjc3RhdF9lbGxpcHNlKCkgKwogIHhsYWIocGFzdGUwKCJQQzEgKCIscGMucGVyWzFdLCIlIiwiKSIpKSArIAogIHlsYWIocGFzdGUwKCJQQzIgKCIscGMucGVyWzJdLCIlIiwiKSIpKSArCiAgbGFicyh0aXRsZT0iUy4gcGFwaWxsb3N1czogUHJpbmNpcGFsIENvbXBvbmVudHMgQW5hbHlzaXMgb2YgUk5Bc2VxIFNhbXBsZXMiLAogICAgICAgY2FwdGlvbiA9ICJOb3RlOiBhbmFseXNpcyBpcyBibGluZCB0byBsaWZlIHN0YWdlIGlkZW50aXR5LiIsCiAgICAgICBzdWJ0aXRsZSA9IkFsbCBzYW1wbGVzL2dyb3VwcyIsCiAgICAgICBmaWxsID0gIkxpZmUgU3RhZ2UiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoLjMsIC4zKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKC4zLCAuMykpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV9idygpCmBgYAoKIyMjIFBDQSBQbG90ClBsb3Qgb2YgdGhlIHNhbXBsZXMgaW4gUENBIHNwYWNlLiBGaWxsIGNvbG9yIGluZGljYXRlcyBsaWZlIHN0YWdlLiAgCmBgYHtyIGVjaG8gPSBGQUxTRX0KcDMKYGBgIAoKYGBge3IgbXVsdGl2YXJpYXRlLjR9CiMgQ3JlYXRlIGEgUENBICdzbWFsbCBtdWx0aXBsZXMnIGNoYXJ0IC0tLS0KcGNhLnJlcy5kZiA8LSBwY2EucmVzJHhbLDE6M10gJT4lIAogIGFzX3RpYmJsZSgpICU+JQogIGFkZF9jb2x1bW4oc2FtcGxlID0gdGFyZ2V0cyRzYW1wbGUsCiAgICAgICAgICAgICBncm91cCA9IHRhcmdldHMkZ3JvdXApCgpwY2EucGl2b3QgPC0gcGl2b3RfbG9uZ2VyKHBjYS5yZXMuZGYsICMgZGF0YWZyYW1lIHRvIGJlIHBpdm90ZWQKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xzID0gUEMxOlBDMywgIyBjb2x1bW4gbmFtZXMgdG8gYmUgc3RvcmVkIGFzIGEgU0lOR0xFIHZhcmlhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiUEMiLCAjIG5hbWUgb2YgdGhhdCBuZXcgdmFyaWFibGUgKGNvbHVtbikKICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAibG9hZGluZ3MiKSAjIG5hbWUgb2YgbmV3IHZhcmlhYmxlIChjb2x1bW4pIHN0b3JpbmcgYWxsIHRoZSB2YWx1ZXMgKGRhdGEpClBDMTwtc3Vic2V0KHBjYS5waXZvdCwgUEMgPT0gIlBDMSIpClBDMiA8LXN1YnNldChwY2EucGl2b3QsIFBDID09ICJQQzIiKQojUEMzIDwtIHN1YnNldChwY2EucGl2b3QsIFBDID09ICJQQzMiKQojUEM0IDwtIHN1YnNldChwY2EucGl2b3QsIFBDID09ICJQQzQiKQoKcDY8LWdncGxvdChwY2EucGl2b3QpICsKICBhZXMoeD1zYW1wbGUsIHk9bG9hZGluZ3MpICsgIyB5b3UgY291bGQgaXRlcmF0aXZlbHkgJ3BhaW50JyBkaWZmZXJlbnQgY292YXJpYXRlcyBvbnRvIHRoaXMgcGxvdCB1c2luZyB0aGUgJ2ZpbGwnIGFlcwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgZmlsbCA9IGJyZXdlci5wYWwoOCwiUGFzdGVsMiIpWzhdKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKwogIGZhY2V0X3dyYXAoflBDKSArCiAgZ2VvbV9iYXIoZGF0YSA9IFBDMSwgc3RhdCA9ICJpZGVudGl0eSIsIGFlcyhmaWxsID0gZ3JvdXApKSArCiAgZ2VvbV9iYXIoZGF0YSA9IFBDMiwgc3RhdCA9ICJpZGVudGl0eSIsIGFlcyhmaWxsID0gZ3JvdXApKSArCiAgbGFicyh0aXRsZT0iUy4gcGFwaWxsb3N1czogUENBICdzbWFsbCBtdWx0aXBsZXMnIHBsb3QiLAogICAgICAgZmlsbCA9ICJMaWZlIFN0YWdlL1NvdXJjZSIsCiAgICAgICBzdWJ0aXRsZSA9IkFsbCBzYW1wbGVzL2dyb3VwcyIpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IHRhcmdldHMkc2FtcGxlLCBsYWJlbHMgPSB0YXJnZXRzJGdyb3VwKSArCiAgdGhlbWVfYncoKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKIyMjIFBDQSAiU21hbGwgTXVsdGlwbGVzIiBQbG90CmBgYHtyIGVjaG8gPSBGQUxTRX0KcDYKYGBgCgoKIyMgSGVhdG1hcCBvZiBHZW5lIEV4cHJlc3Npb24gQWNyb3NzIExpZmUgU3RhZ2VzICAKTWFrZSBhIGhlYXRtYXAgZm9yIGFsbCB0aGUgZ2VuZXMgdXNpbmcgdGhlIExvZzJDUE0gdmFsdWVzLiAgCmBgYHtyIGdlbmUuZXhwcmVzc2lvbi5oZWF0bWFwLCBldmFsID0gVFJVRX0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoaGVhdG1hcGx5KQp9KQojIE1ha2UgYSBoZWF0bWFwIGZvciBhbGwgdGhlIGdlbmVzIHVzaW5nIHRoZSBMb2cyQ1BNIHZhbHVlcwoKZGlmZkdlbmVzIDwtIHYuREVHTGlzdC5maWx0ZXJlZC5ub3JtJEUgJT4lCiAgYXNfdGliYmxlKHJvd25hbWVzID0gImdlbmVJRCIsIC5uYW1lX3JlcGFpciA9ICJ1bmlxdWUiKSAlPiUKICBkcGx5cjo6c2VsZWN0KCFnZW5lSUQpICU+JQogIGFzLm1hdHJpeCgpCnJvd25hbWVzKGRpZmZHZW5lcykgPC0gcm93bmFtZXModi5ERUdMaXN0LmZpbHRlcmVkLm5vcm0kRSkKY29sbmFtZXMoZGlmZkdlbmVzKSA8LSBhcy5jaGFyYWN0ZXIodi5ERUdMaXN0LmZpbHRlcmVkLm5vcm0kdGFyZ2V0cyRncm91cCkKY2x1c3RDb2x1bW5zIDwtIGhjbHVzdChhcy5kaXN0KDEtY29yKGRpZmZHZW5lcywgbWV0aG9kPSJzcGVhcm1hbiIpKSwgbWV0aG9kPSJjb21wbGV0ZSIpCmNsdXN0Um93cyA8LSBoY2x1c3QoYXMuZGlzdCgxLWNvcih0KGRpZmZHZW5lcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPSJwZWFyc29uIikpLCAKICAgICAgICAgICAgICAgICAgICBtZXRob2Q9ImNvbXBsZXRlIikgCnBhcihjZXgubWFpbj0xLjIpCgpzaG93dGlja2xhYmVscyA8LSBjKFRSVUUsRkFMU0UpCnA8LXBoZWF0bWFwKGRpZmZHZW5lcywKICAgICAgICAgICAgY29sb3IgPSBSZEJ1KDc1KSwKICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gY2x1c3RSb3dzLAogICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBjbHVzdENvbHVtbnMsCiAgICAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGLAogICAgICAgICAgICBzY2FsZSA9ICJyb3ciLAogICAgICAgICAgICBhbmdsZV9jb2wgPSA0NSwKICAgICAgICAgICAgbWFpbiA9ICJTLiBwYXBpbGxvc3VzOiBMb2cyIENvdW50cyBQZXIgTWlsbGlvbiAoQ1BNKSBFeHByZXNzaW9uIEFjcm9zcyBMaWZlIFN0YWdlcyIKICAgICAgICAgIAopCgpgYGAKCgojIyBEaWZmZXJlbnRpYWxseSBFeHByZXNzZWQgR2VuZXMKVGhpcyBjaHVuayB1c2VzIGEgdmFyaWFuY2Utc3RhYmlsaXplZCBER0VMaXN0IG9mIGZpbHRlcmVkIGFuZCBub3JtYWxpemVkIGFidW5kYW5jZSBkYXRhLiBUaGVzZSBkYXRhL3Jlc3VsdHMgYXJlIGV4YW1wbGVzLCBhIHJlc3BvbnNpdmUgdmVyc2lvbiBvZiB0aGlzIGNvZGUgaXMgYXZhbGlhYmxlIGluIGEgU2hpbnkgQXBwLiAgCmBgYHtyIERFRywgZXZhbD1UUlVFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1UUlVFfQojIEludHJvZHVjdGlvbiB0byB0aGlzIGNodW5rIC0tLS0KIyBCZWNhdXNlIHdlIGhhdmUgYWNjZXNzIHRvIGJpb2xvZ2ljYWwgYW5kIHRlY2huaWNhbCByZXBsaWNhdGVzLCB3ZSBjYW4gdXNlIHN0YXRpc3RpY2FsIHRvb2xzIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcwojIFVzZWZ1bCByZWFkaW5nIG9uIGRpZmZlcmVudGlhbCBleHByZXNzaW9uOiBodHRwczovL3VjZGF2aXMtYmlvaW5mb3JtYXRpY3MtdHJhaW5pbmcuZ2l0aHViLmlvLzIwMTgtSnVuZS1STkEtU2VxLVdvcmtzaG9wL3RodXJzZGF5L0RFLmh0bWwKCiMgTG9hZCBwYWNrYWdlcyAtLS0tCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyh7CiAgbGlicmFyeSh0aWR5dmVyc2UpCiAgbGlicmFyeShsaW1tYSkgIyBkaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uIHVzaW5nIGxpbmVhciBtb2RlbGluZwogIGxpYnJhcnkoZWRnZVIpCiAgbGlicmFyeShndCkgCiAgbGlicmFyeShEVCkgCiAgbGlicmFyeShwbG90bHkpCiAgbGlicmFyeShnZ3RoZW1lcykKICBsaWJyYXJ5KFJDb2xvckJyZXdlcikKICBzb3VyY2UoIi4uL1N0cm9uZ3lsb2lkZXNfUk5Bc2VxX0Jyb3dzZXIvU2VydmVyL3RoZW1lX1B1YmxpY2F0aW9uLlIiKQp9KQoKZGlmZkdlbmVzLmRmIDwtIHYuREVHTGlzdC5maWx0ZXJlZC5ub3JtJEUgJT4lCiAgYXNfdGliYmxlKHJvd25hbWVzID0gImdlbmVJRCIsIC5uYW1lX3JlcGFpciA9ICJ1bmlxdWUiKQoKIyBTZXQgRXhwcmVzc2lvbiB0aHJlc2hvbGQgdmFsdWVzIGZvciBwbG90dGluZyBhbmQgc2F2aW5nIERFR3MgLS0tLQphZGouUC50aHJlc2ggPC0gMC4wNQpsZmMudGhyZXNoIDwtIDEgCgpncm91cCA8LSBmYWN0b3Iodi5ERUdMaXN0LmZpbHRlcmVkLm5vcm0kdGFyZ2V0cyRncm91cCkKZGVzaWduIDwtIG1vZGVsLm1hdHJpeCh+MCArIGdyb3VwKSAjIG5vIGludGVyY2VwdC9ibG9ja2luZyBmb3IgbWF0cml4LCBjb21wYXJpc29ucyBhY3Jvc3MgZ3JvdXAKY29sbmFtZXMoZGVzaWduKSA8LSBsZXZlbHMoZ3JvdXApCgoKIyBGaXQgYSBsaW5lYXIgbW9kZWwgdG8gdGhlIGRhdGEgLS0tLQpmaXQgPC0gbG1GaXQodi5ERUdMaXN0LmZpbHRlcmVkLm5vcm0sIGRlc2lnbiA9IGRlc2lnbikKCiMgQXMgYW4gZXhhbXBsZSwgZ2VuZXJhdGUgY29tcGFyaXNvbiBtYXRyaXggZm9yIGEgcGFpcndpc2UgY29tcGFyaXNvbiAtLS0tCiMgaUwzcyB2cyBGTEYKIyBOb3RlIHRoYXQgdGhlIHRhcmdldC9jb250cmFzdCBnb3VwcyB3aWxsIGJlIGRpdmlkZWQgYnkgdGhlIG51bWJlciBvZiBsaWZlIAojIHN0YWdlIGdyb3VwcyBlLmcuIFBGK0ZMRi8yIC0gaUwzK2lMM2ErcGZMMStwcEwxK3BwTDMvNQpjb21wYXJpc29uIDwtIGMoJyhpTDMpLShGTEYpJykKCnRhcmdldFN0YWdlPC0gY29tcGFyaXNvbiAlPiUKICBzdHJfc3BsaXQocGF0dGVybj0iLSIsIHNpbXBsaWZ5ID0gVCkgJT4lCiAgLlssMV0gJT4lCiAgZ3N1YigiKCIsICIiLCAuLCBmaXhlZCA9IFRSVUUpICU+JQogIGdzdWIoIikiLCAiIiwgLiwgZml4ZWQgPSBUUlVFKSAlPiUKICBzdHJfc3BsaXQocGF0dGVybiA9ICJcXCsiLCBzaW1wbGlmeSA9IFQpCgpjb250cmFzdFN0YWdlPC1jb21wYXJpc29uICU+JQogIHN0cl9zcGxpdChwYXR0ZXJuPSItIiwgc2ltcGxpZnkgPSBUKSAlPiUKICAuWywyXSAlPiUKICBnc3ViKCIoIiwgIiIsIC4sIGZpeGVkID0gVFJVRSkgJT4lCiAgZ3N1YigiKSIsICIiLCAuLCBmaXhlZCA9IFRSVUUpICAlPiUKICBzdHJfc3BsaXQocGF0dGVybiA9ICJcXCsiLCBzaW1wbGlmeSA9IFQpCgpjb21wYXJpc29uPC0gc2FwcGx5KHNlcV9hbG9uZyhjb21wYXJpc29uKSxmdW5jdGlvbih4KXsKICB0UyA8LSBhcy52ZWN0b3IodGFyZ2V0U3RhZ2VbeCxdKSAlPiUKICAgIC5bLiAhPSAiIl0gCiAgY1MgPC0gYXMudmVjdG9yKGNvbnRyYXN0U3RhZ2VbeCxdKSAlPiUKICAgIC5bLiAhPSAiIl0gCiAgcGFzdGUocGFzdGUwKHRTLCAKICAgICAgICAgICAgICAgY29sbGFwc2UgPSAiKyIpICU+JQogICAgICAgICAgcGFzdGUwKCIoIiwuLCIpLyIsbGVuZ3RoKHRTKSksCiAgICAgICAgcGFzdGUwKGNTLCAKICAgICAgICAgICAgICAgY29sbGFwc2UgPSAiKyIpICU+JQogICAgICAgICAgcGFzdGUwKCIoIiwuLCIpLyIsbGVuZ3RoKGNTKSksCiAgICAgICAgc2VwID0gIi0iKQogIAp9KQoKIyBHZW5lcmF0ZSBjb250cmFzdCBtYXRyaXggLS0tLQpjb250cmFzdC5tYXRyaXggPC0gbWFrZUNvbnRyYXN0cyhjb250cmFzdHMgPSBjb21wYXJpc29uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHM9ZGVzaWduKQoKIyBleHRyYWN0IHRoZSBsaW5lYXIgbW9kZWwgZml0IC0tLS0tCmZpdHMgPC0gY29udHJhc3RzLmZpdChmaXQsIGNvbnRyYXN0Lm1hdHJpeCkKIyBlbXBpcmljYWwgYmF5ZXMgc21vb3RoaW5nIG9mIGdlbmUtd2lzZSBzdGFuZGFyZCBkZXZpYXRpb25zIHByb3ZpZGVzIGluY3JlYXNlZCBwb3dlciAoc2VlOiBodHRwczovL3d3dy5kZWdydXl0ZXIuY29tL2RvaS8xMC4yMjAyLzE1NDQtNjExNS4xMDI3KQplYkZpdCA8LSBlQmF5ZXMoZml0cykKCiMgUHVsbCBvdXQgdGhlIERFR3MgdGhhdCBwYXNzIGEgc3BlY2lmaWMgdGhyZXNob2xkIGZvciBhbGwgcGFpcndpc2UgY29tcGFyaXNvbnMgLS0tLQojIEFkanVzdCBmb3IgbXVsdGlwbGUgY29tcGFyaXNvbnMgdXNpbmcgbWV0aG9kID0gZ2xvYmFsLiAKcmVzdWx0cyA8LSBkZWNpZGVUZXN0cyhlYkZpdCwgbWV0aG9kPSJnbG9iYWwiLCBhZGp1c3QubWV0aG9kPSJCSCIsIHAudmFsdWUgPSBhZGouUC50aHJlc2gpCgpyZWNvZGUwMTwtIGZ1bmN0aW9uKHgpewogIGNhc2Vfd2hlbih4ID09IDEgfiAiVXAiLAogICAgICAgICAgICB4ID09IC0xIH4gIkRvd24iLAogICAgICAgICAgICB4ID09IDAgfiAiTm90U2lnIikKfQpkaWZmRGVzYyA8LSByZXN1bHRzICU+JQogIGFzX3RpYmJsZShyb3duYW1lcyA9ICJnZW5lSUQiKSAlPiUKICBkcGx5cjo6bXV0YXRlKGFjcm9zcygtZ2VuZUlELCB1bmNsYXNzKSkgJT4lCiAgZHBseXI6Om11dGF0ZShhY3Jvc3Mod2hlcmUoaXMuZG91YmxlKSwgcmVjb2RlMDEpKQoKIyBGdW5jdGlvbiB0aGF0IGlkZW50aWZpZXMgdG9wIERFR3MgYmV0d2VlbiBhIHNwZWNpZmljIGNvbnRyYXN0IC0tLS0KY2FsY19ERUdfdGJsIDwtIGZ1bmN0aW9uIChlYkZpdCwgY29lZikgewogIG15VG9wSGl0cy5kZiA8LSBsaW1tYTo6dG9wVGFibGUoZWJGaXQsIGFkanVzdCA9IkJIIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmPWNvZWYsIG51bWJlcj00MDAwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3J0LmJ5PSJsb2dGQyIpICU+JQogICAgYXNfdGliYmxlKHJvd25hbWVzID0gImdlbmVJRCIpICU+JQogICAgZHBseXI6OnJlbmFtZSh0U3RhdGlzdGljID0gdCwgTG9nT2RkcyA9IEIsIEJILmFkai5QLlZhbCA9IGFkai5QLlZhbCkgJT4lCiAgICBkcGx5cjo6cmVsb2NhdGUoVW5pUHJvdEtCLCBEZXNjcmlwdGlvbiwgSW50ZXJQcm8sIEdPX3Rlcm0sIAogICAgICAgICAgICAgICAgICAgIEluLnN1YmNsYWRlX2dlbmVJRCwgSW4uc3ViY2xhZGVfcGVyY2VudF9ob21vbG9neSwKICAgICAgICAgICAgICAgICAgICBPdXQuc3ViY2xhZGVfZ2VuZUlELCBPdXQuc3ViY2xhZGVfcGVyY2VudF9ob21vbG9neSwKICAgICAgICAgICAgICAgICAgICBDZV9nZW5lSUQsIENlX3BlcmNlbnRfaG9tb2xvZ3ksIC5hZnRlciA9IExvZ09kZHMpCiAgCiAgbXlUb3BIaXRzLmRmCn0KCmxpc3QubXlUb3BIaXRzLmRmIDwtIHNhcHBseShjb21wYXJpc29uLCBmdW5jdGlvbih5KXsKICBjYWxjX0RFR190YmwoZWJGaXQsIHkpfSwgCiAgc2ltcGxpZnkgPSBGQUxTRSwgCiAgVVNFLk5BTUVTID0gVFJVRSkKCmxpc3QubXlUb3BIaXRzLmRmIDwtIHNhcHBseShjb21wYXJpc29uLCBmdW5jdGlvbih5KXsKICBsaXN0Lm15VG9wSGl0cy5kZltbeV1dICU+JQogICAgZHBseXI6OnNlbGVjdChnZW5lSUQsIAogICAgICAgICAgICAgICAgICBsb2dGQywgCiAgICAgICAgICAgICAgICAgIEJILmFkai5QLlZhbDpDZV9wZXJjZW50X2hvbW9sb2d5KX0sCiAgc2ltcGxpZnkgPSBGQUxTRSwgCiAgVVNFLk5BTUVTID0gVFJVRSkKCiMgR2V0IGxvZzJDUE0gdmFsdWVzIGFuZCB0aHJlc2hvbGQgaW5mb3JtYXRpb24gZm9yIGdlbmVzIG9mIGludGVyZXN0Cmxpc3QubXlUb3BIaXRzLmRmIDwtIHNhcHBseShzZXFfYWxvbmcoY29tcGFyaXNvbiksIGZ1bmN0aW9uKHkpewogIHRTPC0gdGFyZ2V0U3RhZ2VbeSxdW3RhcmdldFN0YWdlW3ksXSE9IiJdCiAgY1M8LSBjb250cmFzdFN0YWdlW3ksXVtjb250cmFzdFN0YWdlW3ksXSE9IiJdCiAgCiAgY29uY2F0X25hbWUgPC0gZnVuY3Rpb24oeCkgewogICAgaWZlbHNlKHggPT0gInRhcmdldCIsIAogICAgICAgICAgIHBhc3RlKHRTLCBjb2xsYXBzZSA9ICIrIiksIAogICAgICAgICAgIHBhc3RlKGNTLCBjb2xsYXBzZSA9ICIrIikpCiAgfQogIAogIGdyb3VwQXZncyA8LSBkaWZmR2VuZXMuZGYgJT4lCiAgICBkcGx5cjo6c2VsZWN0KGdlbmVJRCwgc3RhcnRzX3dpdGgocGFzdGUwKHRTLCItIikpLCAKICAgICAgICAgICAgICAgICAgc3RhcnRzX3dpdGgocGFzdGUwKGNTLCItIikpKSAlPiUKICAgIHBpdm90X2xvbmdlcihjb2xzID0gLWdlbmVJRCwgbmFtZXNfdG8gPSBjKCJncm91cCIsInNhbXBsZSIpLCB2YWx1ZXNfdG8gPSAiQ1BNIiwKICAgICAgICAgICAgICAgICBuYW1lc19zZXAgPSAiLSIpICU+JQogICAgZHBseXI6Om11dGF0ZShjb250cmFzdElEID0gaWZfZWxzZShncm91cCAlaW4lIHRTLCJ0YXJnZXQiLCAiY29udHJhc3QiKSkgJT4lCiAgICBncm91cF9ieShnZW5lSUQsIGNvbnRyYXN0SUQpICU+JQogICAgZHBseXI6OnNlbGVjdCgtc2FtcGxlKSAlPiUKICAgIHN1bW1hcml6ZShtZWFuID0gbWVhbihDUE0pLCAuZ3JvdXBzID0gImRyb3BfbGFzdCIpICU+JQogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGNvbnRyYXN0SUQsIHZhbHVlc19mcm9tID0gbWVhbikgJT4lCiAgICBkcGx5cjo6cmVsb2NhdGUoY29udHJhc3QsIC5hZnRlciA9IHRhcmdldCkgJT4lCiAgICBkcGx5cjo6cmVuYW1lX3dpdGgoY29uY2F0X25hbWUsIC1nZW5lSUQpICU+JQogICAgZHBseXI6OnJlbmFtZV93aXRoKC5jb2xzID0tZ2VuZUlELCAuZm4gPSB+IHBhc3RlMCgiYXZnXygiLC54LCIpIikpCiAgCiAgZGlmZkdlbmVzLmRmICU+JQogICAgZHBseXI6OnNlbGVjdChnZW5lSUQsIHN0YXJ0c193aXRoKHBhc3RlMCh0UywiLSIpKSwgCiAgICAgICAgICAgICAgICAgIHN0YXJ0c193aXRoKHBhc3RlMChjUywiLSIpKSkgJT4lCiAgICBsZWZ0X2pvaW4oZ3JvdXBBdmdzLCBieSA9ICJnZW5lSUQiKSAlPiUKICAgIGxlZnRfam9pbihsaXN0Lm15VG9wSGl0cy5kZltbeV1dLC4sIGJ5ID0gImdlbmVJRCIpICU+JQogICAgbGVmdF9qb2luKGRwbHlyOjpzZWxlY3QoZGlmZkRlc2MsZ2VuZUlELGNvbXBhcmlzb25beV0pLCBieSA9ICJnZW5lSUQiKSAlPiUKICAgIGRwbHlyOjpyZW5hbWUoREVHX0Rlc2M9Y29tcGFyaXNvblt5XSkgJT4lCiAgICBkcGx5cjo6cmVsb2NhdGUoREVHX0Rlc2MpICU+JQogICAgZHBseXI6OnJlbG9jYXRlKGxvZ0ZDOkNlX3BlcmNlbnRfaG9tb2xvZ3ksIC5hZnRlciA9IGxhc3RfY29sKCkpCiAgCn0sCnNpbXBsaWZ5ID0gRkFMU0UpCgpjb21wYXJpc29uIDwtIGdzdWIoIi9bMC05XSoiLCIiLCBjb21wYXJpc29uKQpuYW1lcyhsaXN0Lm15VG9wSGl0cy5kZikgPC0gY29tcGFyaXNvbgoKbGlzdC5teVRvcEhpdHMuZGYgPC0gc2FwcGx5KGNvbXBhcmlzb24sIGZ1bmN0aW9uKHkpewogIGxpc3QubXlUb3BIaXRzLmRmW1t5XV0gJT4lCiAgICBkcGx5cjo6bXV0YXRlKERFR19EZXNjID0gY2FzZV93aGVuKERFR19EZXNjID09ICJVcCIgfiBwYXN0ZTAoIlVwIGluICIsIHN0cl9zcGxpdCh5LCctJyxzaW1wbGlmeSA9IFQpWzEsMV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBERUdfRGVzYyA9PSAiRG93biIgfiBwYXN0ZTAoIkRvd24gaW4gIiwgc3RyX3NwbGl0KHksJy0nLHNpbXBsaWZ5ID0gVClbMSwxXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERFR19EZXNjID09ICJOb3RTaWciIH4gIk5vdFNpZyIpKSAKfSwKc2ltcGxpZnkgPSBGQUxTRSwgClVTRS5OQU1FUyA9IFRSVUUpCgojIFBDMSBWb2xjYW5vIFBsb3QgYW5kIEludGVyYWN0aXZlIFRhYmxlIC0tLS0KdnBsb3QxIDwtIGdncGxvdChsaXN0Lm15VG9wSGl0cy5kZltbMV1dKSArCiAgYWVzKHk9LWxvZzEwKEJILmFkai5QLlZhbCksIHg9bG9nRkMsIHRleHQgPSBwYXN0ZShnZW5lSUQsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsb2dGQzoiLCByb3VuZChsb2dGQywgZGlnaXRzID0gMiksICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwLXZhbDoiLCBmb3JtYXQoQkguYWRqLlAuVmFsLCBkaWdpdHMgPSAzLCBzY2llbnRpZmljID0gVFJVRSkpKSArCiAgZ2VvbV9wb2ludChzaXplPTIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAoYWRqLlAudGhyZXNoKSwgCiAgICAgICAgICAgICBsaW5ldHlwZT0ibG9uZ2Rhc2giLCAKICAgICAgICAgICAgIGNvbG91cj0iZ3JleSIsIAogICAgICAgICAgICAgc2l6ZT0xKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGxmYy50aHJlc2gsIAogICAgICAgICAgICAgbGluZXR5cGU9ImxvbmdkYXNoIiwgCiAgICAgICAgICAgICBjb2xvdXI9IiNCRTY4NEQiLCAKICAgICAgICAgICAgIHNpemU9MSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IC1sZmMudGhyZXNoLCAKICAgICAgICAgICAgIGxpbmV0eXBlPSJsb25nZGFzaCIsIAogICAgICAgICAgICAgY29sb3VyPSIjMkM0NjdBIiwgCiAgICAgICAgICAgICBzaXplPTEpICsKICBsYWJzKHRpdGxlID0gcGFzdGUwKCdTLiBwYXBpbGxvc3VzLCBQYWlyd2lzZSBDb21wYXJpc29uOiAnLAogICAgICAgICAgICAgICAgICAgICAgZ3N1YignLScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICcgdnMgJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcGFyaXNvblsxXSkpLAogICAgICAgc3VidGl0bGUgPSBwYXN0ZTAoImdyZXkgbGluZTogcCA9ICIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZGouUC50aHJlc2gsICI7IGNvbG9yZWQgbGluZXM6IGxvZy1mb2xkIGNoYW5nZSA9ICIsIGxmYy50aHJlc2gpLAogICAgICAgY29sb3IgPSAiR2VuZUlEcyIpICsKICB0aGVtZV9QdWJsaWNhdGlvbigpIAp2cGxvdDEKCiMgSW50ZXJhY3RpdmUgVGFibGVzCnl5PC0gMQp0UzwtIHRhcmdldFN0YWdlW3l5LF1bdGFyZ2V0U3RhZ2VbeXksXSE9IiJdCmNTPC0gY29udHJhc3RTdGFnZVt5eSxdW2NvbnRyYXN0U3RhZ2VbeXksXSE9IiJdCnNhbXBsZS5udW0udFMgPC0gc2FwcGx5KHRTLCBmdW5jdGlvbih4KSB7Y29sU3Vtcyh2LkRFR0xpc3QuZmlsdGVyZWQubm9ybSRkZXNpZ24pW1t4XV19KSAlPiUgc3VtKCkKc2FtcGxlLm51bS5jUyA8LSBzYXBwbHkoY1MsIGZ1bmN0aW9uKHgpIHtjb2xTdW1zKHYuREVHTGlzdC5maWx0ZXJlZC5ub3JtJGRlc2lnbilbW3hdXX0pICU+JSBzdW0oKQoKCm5fbnVtX2NvbHMgPC0gc2FtcGxlLm51bS50UyArIHNhbXBsZS5udW0uY1MgKyA1CmluZGV4X2hvbW9sb2dzIDwtIGxlbmd0aChjb2xuYW1lcyhsaXN0Lm15VG9wSGl0cy5kZltbeXldXSkpIC0gNQoKCkxTLmRhdGF0YWJsZSA8LSBsaXN0Lm15VG9wSGl0cy5kZltbeXldXSAlPiUKICBEVDo6ZGF0YXRhYmxlKHJvd25hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICBjYXB0aW9uID0gaHRtbHRvb2xzOjp0YWdzJGNhcHRpb24oCiAgICAgICAgICAgICAgICAgIHN0eWxlID0gJ2NhcHRpb24tc2lkZTogdG9wOyB0ZXh0LWFsaWduOiBsZWZ0OyBjb2xvcjogYmxhY2snLAogICAgICAgICAgICAgICAgICBodG1sdG9vbHM6OnRhZ3MkYignRGlmZmVyZW50aWFsbHkgRXhwcmVzc2VkIEdlbmVzIGluJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGh0bWx0b29sczo6dGFncyRlbSgnUy4gcGFwaWxsb3N1cycpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3N1YignLScsJyB2cyAnLGNvbXBhcmlzb25beXldKSksCiAgICAgICAgICAgICAgICAgIGh0bWx0b29sczo6dGFncyRicigpLAogICAgICAgICAgICAgICAgICAiVGhyZXNob2xkOiBwIDwgIiwKICAgICAgICAgICAgICAgICAgYWRqLlAudGhyZXNoLCAiOyBsb2ctZm9sZCBjaGFuZ2UgPiAiLAogICAgICAgICAgICAgICAgICBsZmMudGhyZXNoLAogICAgICAgICAgICAgICAgICBodG1sdG9vbHM6OnRhZ3MkYnIoKSwKICAgICAgICAgICAgICAgICAgJ1ZhbHVlcyA9IGxvZzIgY291bnRzIHBlciBtaWxsaW9uJyksCiAgICAgICAgICAgICAgICBvcHRpb25zID0gbGlzdChhdXRvV2lkdGggPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Nyb2xsWCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY3JvbGxZID0gJzMwMHB4JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbENvbGxhcHNlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyID0gbGlzdChuX251bV9jb2xzLTEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdkZXNjJyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWFyY2hIaWdobGlnaHQgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VMZW5ndGggPSAyNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGhNZW51ID0gYygiNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjI1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI1MCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAwIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5EZWZzID0gbGlzdCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXRzID0gKChuX251bV9jb2xzICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuZGVyID0gSlMoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZnVuY3Rpb24oZGF0YSwgcm93KSB7IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkYXRhLnRvRXhwb25lbnRpYWwoMSk7IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ9IikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXRzID0gKChuX251bV9jb2xzICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA0KToobl9udW1fY29scyArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbmRlciA9IEpTKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImZ1bmN0aW9uKGRhdGEsIHR5cGUsIHJvdywgbWV0YSkgeyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmV0dXJuIHR5cGUgPT09ICdkaXNwbGF5JyAmJiBkYXRhLmxlbmd0aCA+IDIwID8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIic8c3BhbiB0aXRsZT1cIicgKyBkYXRhICsgJ1wiPicgKyBkYXRhLnN1YnN0cigwLCAyMCkgKyAnLi4uPC9zcGFuPicgOiBkYXRhOyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAifSIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QodGFyZ2V0cyA9ICJfYWxsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz0iZHQtcmlnaHQiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd0NhbGxiYWNrID0gSlMoYygKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImZ1bmN0aW9uKHJvdywgZGF0YSl7IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiAgZm9yKHZhciBpPTA7IGk8ZGF0YS5sZW5ndGg7IGkrKyl7IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiAgICBpZihkYXRhW2ldID09PSBudWxsKXsiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiICAgICAgJCgndGQ6ZXEoJytpKycpJywgcm93KS5odG1sKCdOQScpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiAgICAgICAgLmNzcyh7J2NvbG9yJzogJ3JnYigxNTEsMTUxLDE1MSknLCAnZm9udC1zdHlsZSc6ICdpdGFsaWMnfSk7IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiAgICB9IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiAgfSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ9IiAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICApKSAKTFMuZGF0YXRhYmxlIDwtIExTLmRhdGF0YWJsZSAlPiUKICBEVDo6Zm9ybWF0Um91bmQoY29sdW1ucz1jKDM6bl9udW1fY29scyksIAogICAgICAgICAgICAgICAgICBkaWdpdHM9MykKCkxTLmRhdGF0YWJsZSA8LSBMUy5kYXRhdGFibGUgJT4lCiAgRFQ6OmZvcm1hdFJvdW5kKGNvbHVtbnM9YyhuX251bV9jb2xzKzIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXhfaG9tb2xvZ3MrMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZGV4X2hvbW9sb2dzKzMpLCAKICAgICAgICAgICAgICAgICAgZGlnaXRzPTIpCgpMUy5kYXRhdGFibGUgPC0gTFMuZGF0YXRhYmxlICU+JQogIERUOjpmb3JtYXRTaWduaWYoY29sdW1ucz1jKG5fbnVtX2NvbHMrMSksIAogICAgICAgICAgICAgICAgICAgZGlnaXRzPTMpCgpMUy5kYXRhdGFibGUKCmBgYAoKIyMgQmVuY2htYXJraW5nClRhYmxlcyB3aXRoIGRhdGEgc3VpdGFibGUgZm9yIGJlbmNobWFya2luZyBhcmUgbm90IGN1cnJlbnRseSBhdmFpbGFibGUuICAKCiMjIEZ1bmN0aW9uYWwgRW5yaWNobWVudCBBbmFseXNpcwpUaGlzIGNvZGUgcHJlcmZvcm0gR1NFQSB1c2luZyB0aGUgY2x1c3RlclByb2ZpbGVyIGxpYnJhcnkuIEFiaWxpdHkgdG8gZG8gdGhpcyBkZXBlbmRzIG9uIHRoZSBhdmFpbGFiaWxpdHkgb2YgZ2VuZSBzZXRzLiBNYWpvciBkYXRhYmFzZXMgKGUuZy4gbXNpZ2RiIGRvbid0IHNlZW0gdG8gaGF2ZSAqU3Ryb25neWxvaWRlcyogaW5mb3JtYXRpb24uIFRoZXkgZG8gaGF2ZSAqQy4gZWxlZ2FucyogZ2VuZSBzZXRzLCBidXQgSSdtIG5vdCBjb252aW5jZWQgdGhlIGhvbW9sb2d5IGluZm9ybWF0aW9uIGlzIGdvb2QgZW5vdWdoIGZvciB0aGUgY29tcGFyaXNvbiB0byBiZSB1bmJpYXNlZC9tZWFuaW5nZnVsLiBJbiBIdW50IGV0IGFsIDIwMTYsIHRoZXJlIGlzIGFuIEVuc2VtYmwgQ29tcGFyYSBwcm90ZWluIGZhbWlseSBzZXQ7IHdlIHdpbGwgdXNlIHRoaXMgYXMgdGhlIGJhc2lzIGZvciBvdXIgZ2VuZSBzZXQgbGlicmFyaWVzLiAgCk5vdGUgdGhhdCB0aGlzIHVzZXMgc3BlY2lmaWMgdHJhbnNjcmlwdCBpbmZvcm1hdGlvbiwgd2hpY2ggSSB0aHJvdyBvdXQgKGUuZy4gU1NUUF8wMDAxMTM3NDAwLjIgaXMgcmVjb2RlZCBhcyBTU1RQXzAwMDExMzc0MDApLgoKR2l2ZW4gYSBwcmlvcmkgZGVmaW5lZCBzZXQgb2YgZ2VuZSBTIChlLmcuLCBnZW5lcyBzaGFyZWluZyB0aGUgc2FtZSBETyBjYXRlZ29yeSksIHRoZSBnb2FsIG9mIEdTRUEgaXMgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIG1lbWJlcnMgb2YgUyBhcmUgcmFuZG9tbHkgZGlzdHJpYnV0ZWQgdGhyb3VnaG91dCB0aGUgcmFua2VkIGdlbmUgbGlzdCAoTCkgb3IgcHJpbWFyaWx5IGZvdW5kIGF0IHRoZSB0b3Agb3IgYm90dG9tLiAgClRoZXJlIGFyZSB0aHJlZSBrZXkgZWxlbWVudHMgb2YgdGhlIEdTRUEgbWV0aG9kOiAgCioqQ2FsY3VsYXRpb24gb2YgYW4gRW5yaWNobWVudCBTY29yZS4qKiAgClRoZSBlbnJpY2htZW50IHNjb3JlIChFUykgcmVwcmVzZW50IHRoZSBkZWdyZWUgdG8gd2hpY2ggYSBzZXQgUyBpcyBvdmVyLXJlcHJlc2VudGVkIGF0IHRoZSB0b3Agb3IgYm90dG9tIG9mIHRoZSByYW5rZWQgbGlzdCBMLiBUaGUgc2NvcmUgaXMgY2FsY3VsYXRlZCBieSB3YWxraW5nIGRvd24gdGhlIGxpc3QgTCwgaW5jcmVhc2luZyBhIHJ1bm5pbmctc3VtIHN0YXRpc3RpYyB3aGVuIHdlIGVuY291bnRlciBhIGdlbmUgaW4gUyBhbmQgZGVjcmVhc2luZyB3aGVuIGl0IGlzIG5vdC4gVGhlIG1hZ25pdHVkZSBvZiB0aGUgaW5jcmVtZW50IGRlcGVuZHMgb24gdGhlIGdlbmUgc3RhdGlzdGljcyAoZS5nLiwgY29ycmVsYXRpb24gb2YgdGhlIGdlbmUgd2l0aCBwaGVub3R5cGUpLiBUaGUgRVMgaXMgdGhlIG1heGltdW0gZGV2aWF0aW9uIGZyb20gemVybyBlbmNvdW50ZXJlZCBpbiB0aGUgcmFuZG9tIHdhbGs7IGl0IGNvcnJlc3BvbmRzIHRvIGEgd2VpZ2h0ZWQgS29sbW9nb3Jvdi1TbWlybm92LWxpa2Ugc3RhdGlzdGljIChTdWJyYW1hbmlhbiBldCBhbC4gMjAwNSkuICAKKipFc2ltYXRpb24gb2YgU2lnbmlmaWNhbmNlIExldmVsIG9mIEVTLioqICAKVGhlIHAtdmFsdWUgb2YgdGhlIEVTIGlzIGNhbGN1bGF0ZWQgdXNpbmcgcGVybXV0YXRpb24gdGVzdC4gU3BlY2lmaWNhbGx5LCB3ZSBwZXJtdXRlIHRoZSBnZW5lIGxhYmVscyBvZiB0aGUgZ2VuZSBsaXN0IEwgYW5kIHJlY29tcHV0ZSB0aGUgRVMgb2YgdGhlIGdlbmUgc2V0IGZvciB0aGUgcGVybXV0YXRlZCBkYXRhLCB3aGljaCBnZW5lcmF0ZSBhIG51bGwgZGlzdHJpYnV0aW9uIGZvciB0aGUgRVMuIFRoZSBwLXZhbHVlIG9mIHRoZSBvYnNlcnZlZCBFUyBpcyB0aGVuIGNhbGN1bGF0ZWQgcmVsYXRpdmUgdG8gdGhpcyBudWxsIGRpc3RyaWJ1dGlvbi4gIAoqKkFkanVzdG1lbnQgZm9yIE11bHRpcGxlIEh5cG90aGVzaXMgVGVzdGluZy4qKiAgCldoZW4gdGhlIGVudGlyZSBnZW5lIHNldHMgd2VyZSBldmFsdWF0ZWQsIERPU0UgYWRqdXN0IHRoZSBlc3RpbWF0ZWQgc2lnbmlmaWNhbmNlIGxldmVsIHRvIGFjY291bnQgZm9yIG11bHRpcGxlIGh5cG90aGVzaXMgdGVzdGluZyBhbmQgYWxzbyBxLXZhbHVlcyB3ZXJlIGNhbGN1bGF0ZWQgZm9yIEZEUiBjb250cm9sLiAgCgpgYGB7ciBmdW5jdGlvbmFsRW5yaWNobWVudH0KIyBMb2FkIHBhY2thZ2VzIC0tLS0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KHRpZHl2ZXJzZSkKICBsaWJyYXJ5KGxpbW1hKQogIGxpYnJhcnkob3Blbnhsc3gpCiAgbGlicmFyeShncGxvdHMpICNmb3IgaGVhdG1hcHMKICBsaWJyYXJ5KERUKSAjaW50ZXJhY3RpdmUgYW5kIHNlYXJjaGFibGUgdGFibGVzIG9mIG91ciBHU0VBIHJlc3VsdHMKICBsaWJyYXJ5KEdTRUFCYXNlKSAjZnVuY3Rpb25zIGFuZCBtZXRob2RzIGZvciBHZW5lIFNldCBFbnJpY2htZW50IEFuYWx5c2lzCiAgbGlicmFyeShCaW9iYXNlKSAjYmFzZSBmdW5jdGlvbnMgZm9yIGJpb2NvbmR1Y3RvcjsgcmVxdWlyZWQgYnkgR1NFQUJhc2UKICBsaWJyYXJ5KEdTVkEpICNHZW5lIFNldCBWYXJpYXRpb24gQW5hbHlzaXMsIGEgbm9uLXBhcmFtZXRyaWMgYW5kIHVuc3VwZXJ2aXNlZCBtZXRob2QgZm9yIGVzdGltYXRpbmcgdmFyaWF0aW9uIG9mIGdlbmUgc2V0IGVucmljaG1lbnQgYWNyb3NzIHNhbXBsZXMuCiAgbGlicmFyeShncHJvZmlsZXIyKSAjdG9vbHMgZm9yIGFjY2Vzc2luZyB0aGUgR08gZW5yaWNobWVudCByZXN1bHRzIHVzaW5nIGc6UHJvZmlsZXIgd2ViIHJlc291cmNlcwogIGxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKSAjIHByb3ZpZGVzIGEgc3VpdGUgb2YgdG9vbHMgZm9yIGZ1bmN0aW9uYWwgZW5yaWNobWVudCBhbmFseXNpcwogIGxpYnJhcnkobXNpZ2RicikgIyBhY2Nlc3MgdG8gbXNpZ2RiIGNvbGxlY3Rpb25zIGRpcmVjdGx5IHdpdGhpbiBSCiAgbGlicmFyeShlbnJpY2hwbG90KSAjIGdyZWF0IGZvciBtYWtpbmcgdGhlIHN0YW5kYXJkIEdTRUEgZW5yaWNobWVudCBwbG90cwp9KQojIFBpY2sgYSBwYWlyd2lzZSBjb21wYXJpc29uCnl5IDwtIDEKCiMgQ2Fycnkgb3V0IEdPIGVucmljaG1lbnQgdXNpbmcgZ1Byb2ZpbGVyMiAtLS0tCiMgR08gZW5yaWNobWVudCByZXF1aXJlcyBhIHByZS1zZWxlY3RlZCBzZXQgb2YgZ2VuZXMuIENhbiB1c2UgbXVsdGlwbGUgY3JpdGVyaWEgdG8gZG8gdGhhdCBpbml0aWFsIHNlbGVjdGlvbi4KIyBUaGUgR08gdGVybXMgSSdtIGFjY2Vzc2luZyB1c2luZyB0aGUgZ29zdCBhcmUgZnJvbSBIdW50IGV0IGFsIDIwMTYsIEkgYmVsaWV2ZS4KCiMgIyBQQzEgVG9wVGFibGUgUmVzdWx0cwojIGVucmljaGVkLnNldC5wb3MgPC1saXN0Lm15VG9wSGl0cy5kZltbeXldXSAlPiUgCiMgICAgIHNsaWNlX21heChsb2dGQywgcHJvcCA9IC4xKSAjIGdldCB0b3AgMTAlIG9mIGdlbmVzCiMgCiMgZW5yaWNoZWQuc2V0Lm5lZyA8LSBsaXN0Lm15VG9wSGl0cy5kZltbeXldXSAlPiUgCiMgICAgIHNsaWNlX21pbihsb2dGQywgcHJvcCA9IC4xKSAjIGdldCB0b3AgMTAlIG9mIGdlbmVzCiMgCiMgZ29zdC5yZXMucG9zIDwtIGdvc3QobGlzdChUYXJnZXRfVXByZWd1bGF0ZWQgPSBlbnJpY2hlZC5zZXQucG9zJGdlbmVJRCksIG9yZ2FuaXNtID0gInN0c3RlcnByamViNTI4IiwgY29ycmVjdGlvbl9tZXRob2QgPSAiZmRyIikKIyBnb3N0cGxvdChnb3N0LnJlcy5wb3MsIGludGVyYWN0aXZlID0gVCwgY2FwcGVkID0gVCkKIyAKIyBnb3N0LnJlcy5uZWcgPC0gZ29zdChsaXN0KFRhcmdldF9Eb3ducmVndWxhdGVkX0dlbmVzID0gZW5yaWNoZWQuc2V0Lm5lZyRnZW5lSUQpLCBvcmdhbmlzbSA9ICJzdHN0ZXJwcmplYjUyOCIsIGNvcnJlY3Rpb25fbWV0aG9kID0gImZkciIpCiMgZ29zdHBsb3QoZ29zdC5yZXMubmVnLCBpbnRlcmFjdGl2ZSA9IFQsIGNhcHBlZCA9IFQpCgojIFBlcmZvcm0gR1NFQSB1c2luZyBjbHVzdGVyUHJvZmlsZXIgLS0tLQojIFdoaWNoIGxpYnJhcnkgdG8gdXNlIGZvciBpbXBsZW1lbnRhdGlvbj8gQXMgcGVyIGh0dHBzOi8vYWNhZGVtaWMub3VwLmNvbS9iaWIvYWR2YW5jZS1hcnRpY2xlL2RvaS8xMC4xMDkzL2JpYi9iYnoxNTgvNTcyMjM4NDogIkZvciBleHByZXNzaW9uLWJhc2VkIEVBIG9uIHRoZSBmdWxsIGV4cHJlc3Npb24gbWF0cml4Li4uV2hlbiBnaXZlbiByYXcgcmVhZCBjb3VudHMsIHdlIHJlY29tbWVuZCB0byBhcHBseSBhIFZTVCBzdWNoIGFzIHZvb20gWzM5XSB0byBhcnJpdmUgYXQgbGlicmFyeS1zaXplIG5vcm1hbGl6ZWQgbG9nQ1BNcy4iCiMgRm9yIHRlc3Rpbmcgc2VsZi1jb250YWluZWQgbnVsbCBoeXBvdGhlc2lzICh0ZXN0IGZvciBhc3NvY2lhdGlvbiBvZiBhbnkgZ2VuZSBpbiB0aGUgc2V0IHdpdGggdGhlIHBoZW5vdHlwZSksIHVzZSBST0FTVAojIEZvciB0ZXN0aW5nIGNvbXBldGl0aXZlIG51bGwgaHlwb3RoZXNpcyAodGVzdCBmb3IgZXhjZXNzIG9mIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGluIGEgZ2VuZSBzZXQgcmVsYXRpdmUgdG8gZ2VuZXMgb3V0c2lkZSB0aGUgc2V0KSAtICoqdGhlaXIgcmVjb21tZW5kYXRpb24qKiwgdXNlIFBBRE9HIG9yIFNBRkU/CiMgCiMgQWJpbGl0eSB0byBkbyB0aGlzIGRlcGVuZHMgb24gdGhlIGF2YWlsYWJpbGl0eSBvZiBnZW5lIHNldHMuIE1ham9yIGRhdGFiYXNlcyAoZS5nLiBtc2lnZGIgZG9uJ3Qgc2VlbSB0byBoYXZlIFN0cm9uZ3lsb2lkZXMgaW5mb3JtYXRpb24uIFRoZXkgZG8gaGF2ZSBDLiBlbGVnYW5zIGdlbmUgc2V0cywgYnV0IEknbSBub3QgY29udmluY2VkIHRoZSBob21vbG9neSBpbmZvcm1hdGlvbiBpcyBnb29kIGVub3VnaCBmb3IgdGhlIGNvbXBhcmlzb24gdG8gYmUgdW5iaWFzZWQvbWVhbmluZ2Z1bC4gCiMgCgojIEluIEh1bnQgZXQgYWwgMjAxNiwgdGhlcmUgaXMgYW4gRW5zZW1ibCBDb21wYXJhIHByb3RlaW4gZmFtaWx5IHNldAojIE5vdGUgdGhhdCB0aGlzIHVzZXMgc3BlY2lmaWMgdHJhbnNjcmlwdCBpbmZvcm1hdGlvbiwgd2hpY2ggSSB0aHJvdyBvdXQuIAojIChlLmcuIFNTVFBfMDAwMTEzNzQwMC4yIGlzIHJlY29kZWQgYXMgU1NUUF8wMDAxMTM3NDAwKQplbnNDb21wLmdlbmVJRHMgPC0gcmVhZC54bHN4ICgiLi4vRGF0YS9IdW50X1BhcmFzaXRlX0Vuc2VtYmxfQ29tcGFyYS54bHN4IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gMSkgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgZHBseXI6OnNlbGVjdCgtRmFtaWx5Lm1lbWJlcnMpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLUNvbXBhcmEuZmFtaWx5LmlkLCB2YWx1ZXNfdG8gPSAiZ2VuZUlEIikgJT4lCiAgZHBseXI6OnNlbGVjdCgtbmFtZSkgJT4lCiAgZHBseXI6OmZpbHRlcihncmVwbCgiU1BBTF8iLCBnZW5lSUQpKQoKZW5zQ29tcC5nZW5lSURzJGdlbmVJRCA8LSBzdHJfcmVtb3ZlX2FsbChlbnNDb21wLmdlbmVJRHMkZ2VuZUlELCAiXFwuWzAtOV0kIikKZW5zQ29tcC5nZW5lSURzJGdlbmVJRCA8LSBzdHJfcmVtb3ZlX2FsbChlbnNDb21wLmdlbmVJRHMkZ2VuZUlELCAiW2Etel0kIikKCiMgQ29tcGFyZSB0aGVzZSBnZW5lcyB0byB0aGUgbGlzdCBvZiBnZW5lcyBpbiBvdXIgZmlsdGVyZWQsIG5vcm1hbGl6ZWQgbGlzdCAtLS0tCiMgCmNvbXBhcmEuZXhjbHVzaXZlIDwtIHVuaXF1ZShlbnNDb21wLmdlbmVJRHMkZ2VuZUlEKSAlPiUKICBhc190aWJibGVfY29sKGNvbHVtbl9uYW1lID0gImdlbmVJRCIpICU+JQogIGRwbHlyOjphbnRpX2pvaW4oZGlmZkdlbmVzLmRmLCBieSA9ICJnZW5lSUQiKQpwYXN0ZSgnTnVtYmVyIG9mIGdlbmVzIGV4Y2x1c2l2ZSB0byB0aGUgRW5zZW1ibCBDb21wYXJhIExpc3Q6ICcsbnJvdyhjb21wYXJhLmV4Y2x1c2l2ZSkpCgpjb21wYXJhLmFic2VudCA8LSB1bmlxdWUoZW5zQ29tcC5nZW5lSURzJGdlbmVJRCkgJT4lCiAgYXNfdGliYmxlX2NvbChjb2x1bW5fbmFtZSA9ICJnZW5lSUQiKSAlPiUKICBkcGx5cjo6YW50aV9qb2luKGRpZmZHZW5lcy5kZiwuLCBieSA9ICJnZW5lSUQiKSAlPiUKICBkcGx5cjo6c2VsZWN0KGdlbmVJRCkKcGFzdGUoJ051bWJlciBvZiBnZW5lcyBleGNsdXNpdmUgdG8gdGhlIFJOQXNlcSBHZW5lIExpc3Q6ICcsbnJvdyhjb21wYXJhLmFic2VudCkpCgojIEhvdyBtYW55IGdlbmVzIGhhdmUgYXNzb2NpYXRlZCBHTyB0ZXJtcz8gLS0tLQpHTy5wcmVzZW50IDwtIGxpc3QubXlUb3BIaXRzLmRmW1t5eV1dJEdPX3Rlcm0gJT4lCiAgZ3N1YigiTkEiLCBOQSwuKSAlPiUKICBhc190aWJibGVfY29sKGNvbHVtbl9uYW1lID0gIkdPX1Rlcm0iKSAlPiUKICB0aWJibGUoZ2VuZUlEID0gbGlzdC5teVRvcEhpdHMuZGZbW3l5XV0kZ2VuZUlELC4pICU+JQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKEdPX1Rlcm0pKQpwYXN0ZSgnTnVtYmVyIG9mIGdlbmVzIHdpdGggYW4gYXNzb2NpYXRlZCBHTyB0ZXJtOiAnLG5yb3coR08ucHJlc2VudCkpCgojIEFyZSBhbnkgb2YgdGhlc2UgZ2VuZXMgcGFydCBvZiB0aG9zZSBub3QgZm91bmQgaW4gdGhlIGNvbXBhcmEgZGF0YXNldD8gLS0tLSAKR08ucHJlc2VudC5Db21wYXJhLmFic2VudCA8LSBkcGx5cjo6c2VtaV9qb2luKEdPLnByZXNlbnQsIGNvbXBhcmEuYWJzZW50LCBieSA9ICJnZW5lSUQiKQpwYXN0ZSgnTnVtYmVyIG9mIGdlbmVzIHdpdGggR08gdGVybXMgdGhhdCBhcmUgbm90IGZvdW5kIGluIHRoZSBFbnNlbWJsIENvbXBhcmEgTGlzdDogJyxucm93KEdPLnByZXNlbnQuQ29tcGFyYS5hYnNlbnQpKQoKIyBNYWtlIGEgbGlzdCBvZiBnZW5lcwplbnNDb21wLmZhbWlseUlEcyA8LSByZWFkLnhsc3ggKCIuLi9EYXRhL0h1bnRfUGFyYXNpdGVfRW5zZW1ibF9Db21wYXJhLnhsc3giLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29scyA9IGMoMSw0OjYpKSAlPiUKICBhc190aWJibGUoKSAlPiUKICBkcGx5cjo6bXV0YXRlKEZhbWlseV9EZXNjcmlwdGlvbiA9IGRwbHlyOjpjb2FsZXNjZSguJERlc2NyaXB0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJGBUb3AucHJvZHVjdC4obWVtYmVycy53aXRoLmhpdClgLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJGBJbnRlcnByby50b3AuaGl0LihtZW1iZXJzLndpdGguaGl0KWApCiAgKSAlPiUKICBkcGx5cjo6c2VsZWN0KENvbXBhcmEuZmFtaWx5LmlkLCBGYW1pbHlfRGVzY3JpcHRpb24pCgplbnNDb21wIDwtIGxlZnRfam9pbihlbnNDb21wLmdlbmVJRHMsIGVuc0NvbXAuZmFtaWx5SURzLCBieSA9ICJDb21wYXJhLmZhbWlseS5pZCIpICU+JQogIGRwbHlyOjpzZWxlY3QoLUNvbXBhcmEuZmFtaWx5LmlkKSAlPiUKICBkcGx5cjo6cmVuYW1lKGdzX25hbWUgPSBGYW1pbHlfRGVzY3JpcHRpb24sIGdlbmVfc3ltYm9sID0gZ2VuZUlEKSAlPiUKICBkcGx5cjo6cmVsb2NhdGUoZ3NfbmFtZSwgZ2VuZV9zeW1ib2wpCgpybShlbnNDb21wLmdlbmVJRHMsIGVuc0NvbXAuZmFtaWx5SURzKQoKIyBGaWx0ZXIgb3V0IGdlbmVzIHRoYXQgYXJlbid0IHBhcnQgb2Ygb3VyIFJOQXNlcSBkYXRhc2V0CmdlbmVsaXN0IDwtIHYuREVHTGlzdC5maWx0ZXJlZC5ub3JtJGdlbmVzICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAiZ2VuZUlEIikgJT4lCiAgZHBseXI6OnNlbGVjdChnZW5lSUQpCmVuc0NvbXA8LSBlbnNDb21wICU+JQogIGRwbHlyOjpyZW5hbWUoZ2VuZUlEID0gZ2VuZV9zeW1ib2wpICU+JQogIGxlZnRfam9pbihnZW5lbGlzdCwgLiwgYnkgPSAiZ2VuZUlEIikgJT4lCiAgZHBseXI6OnJlbG9jYXRlKGdzX25hbWUsIGdlbmVJRCkKCgojIEdlbmVyYXRlIHJhbmsgb3JkZXJlZCBsaXN0IG9mIGdlbmVzIC0tLS0KbXlkYXRhLmRmLnN1YiA8LSBkcGx5cjo6c2VsZWN0KGxpc3QubXlUb3BIaXRzLmRmW1t5eV1dLCBnZW5lSUQsIGxvZ0ZDKQpteWRhdGEuZ3NlYSA8LSBteWRhdGEuZGYuc3ViJGxvZ0ZDCm5hbWVzKG15ZGF0YS5nc2VhKSA8LSBhcy5jaGFyYWN0ZXIobXlkYXRhLmRmLnN1YiRnZW5lSUQpCm15ZGF0YS5nc2VhIDwtIHNvcnQobXlkYXRhLmdzZWEsIGRlY3JlYXNpbmcgPSBUUlVFKQoKIyBydW4gR1NFQSB1c2luZyB0aGUgJ0dTRUEnIGZ1bmN0aW9uIGZyb20gY2x1c3RlclByb2ZpbGVyCiMgR2l2ZW4gYSBwcmlvcmkgZGVmaW5lZCBzZXQgb2YgZ2VuZSBTIChlLmcuLCBnZW5lcyBzaGFyZWluZyB0aGUgc2FtZSBETyBjYXRlZ29yeSksIHRoZSBnb2FsIG9mIEdTRUEgaXMgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIG1lbWJlcnMgb2YgUyBhcmUgcmFuZG9tbHkgZGlzdHJpYnV0ZWQgdGhyb3VnaG91dCB0aGUgcmFua2VkIGdlbmUgbGlzdCAoTCkgb3IgcHJpbWFyaWx5IGZvdW5kIGF0IHRoZSB0b3Agb3IgYm90dG9tLgojIFRoZXJlIGFyZSB0aHJlZSBrZXkgZWxlbWVudHMgb2YgdGhlIEdTRUEgbWV0aG9kOgojICoqQ2FsY3VsYXRpb24gb2YgYW4gRW5yaWNobWVudCBTY29yZS4qKgojIFRoZSBlbnJpY2htZW50IHNjb3JlIChFUykgcmVwcmVzZW50IHRoZSBkZWdyZWUgdG8gd2hpY2ggYSBzZXQgUyBpcyBvdmVyLXJlcHJlc2VudGVkIGF0IHRoZSB0b3Agb3IgYm90dG9tIG9mIHRoZSByYW5rZWQgbGlzdCBMLiBUaGUgc2NvcmUgaXMgY2FsY3VsYXRlZCBieSB3YWxraW5nIGRvd24gdGhlIGxpc3QgTCwgaW5jcmVhc2luZyBhIHJ1bm5pbmctc3VtIHN0YXRpc3RpYyB3aGVuIHdlIGVuY291bnRlciBhIGdlbmUgaW4gUyBhbmQgZGVjcmVhc2luZyB3aGVuIGl0IGlzIG5vdC4gVGhlIG1hZ25pdHVkZSBvZiB0aGUgaW5jcmVtZW50IGRlcGVuZHMgb24gdGhlIGdlbmUgc3RhdGlzdGljcyAoZS5nLiwgY29ycmVsYXRpb24gb2YgdGhlIGdlbmUgd2l0aCBwaGVub3R5cGUpLiBUaGUgRVMgaXMgdGhlIG1heGltdW0gZGV2aWF0aW9uIGZyb20gemVybyBlbmNvdW50ZXJlZCBpbiB0aGUgcmFuZG9tIHdhbGs7IGl0IGNvcnJlc3BvbmRzIHRvIGEgd2VpZ2h0ZWQgS29sbW9nb3Jvdi1TbWlybm92LWxpa2Ugc3RhdGlzdGljIChTdWJyYW1hbmlhbiBldCBhbC4gMjAwNSkuCiMgKipFc2ltYXRpb24gb2YgU2lnbmlmaWNhbmNlIExldmVsIG9mIEVTLioqCiMgVGhlIHAtdmFsdWUgb2YgdGhlIEVTIGlzIGNhbGN1bGF0ZWQgdXNpbmcgcGVybXV0YXRpb24gdGVzdC4gU3BlY2lmaWNhbGx5LCB3ZSBwZXJtdXRlIHRoZSBnZW5lIGxhYmVscyBvZiB0aGUgZ2VuZSBsaXN0IEwgYW5kIHJlY29tcHV0ZSB0aGUgRVMgb2YgdGhlIGdlbmUgc2V0IGZvciB0aGUgcGVybXV0YXRlZCBkYXRhLCB3aGljaCBnZW5lcmF0ZSBhIG51bGwgZGlzdHJpYnV0aW9uIGZvciB0aGUgRVMuIFRoZSBwLXZhbHVlIG9mIHRoZSBvYnNlcnZlZCBFUyBpcyB0aGVuIGNhbGN1bGF0ZWQgcmVsYXRpdmUgdG8gdGhpcyBudWxsIGRpc3RyaWJ1dGlvbi4KIyAqKkFkanVzdG1lbnQgZm9yIE11bHRpcGxlIEh5cG90aGVzaXMgVGVzdGluZy4qKgojIFdoZW4gdGhlIGVudGlyZSBnZW5lIHNldHMgd2VyZSBldmFsdWF0ZWQsIERPU0UgYWRqdXN0IHRoZSBlc3RpbWF0ZWQgc2lnbmlmaWNhbmNlIGxldmVsIHRvIGFjY291bnQgZm9yIG11bHRpcGxlIGh5cG90aGVzaXMgdGVzdGluZyBhbmQgYWxzbyBxLXZhbHVlcyB3ZXJlIGNhbGN1bGF0ZWQgZm9yIEZEUiBjb250cm9sLgpteUdTRUEucmVzIDwtIEdTRUEobXlkYXRhLmdzZWEsIFRFUk0yR0VORT1lbnNDb21wLCB2ZXJib3NlPUZBTFNFKQpteUdTRUEuZGYgPC0gYXNfdGliYmxlKG15R1NFQS5yZXNAcmVzdWx0KQoKbXlHU0VBLnRibDwtYXNfdGliYmxlKG15R1NFQS5yZXNAcmVzdWx0KSAlPiUKICBkcGx5cjo6c2VsZWN0KC1jKERlc2NyaXB0aW9uLCBwdmFsdWUsIGVucmljaG1lbnRTY29yZSkpICU+JQogIGRwbHlyOjpyZW5hbWUobm9ybWFsaXplZF9FbnJpY2htZW50U2NvcmUgPSBORVMpCgojIHZpZXcgcmVzdWx0cyBhcyBhbiBpbnRlcmFjdGl2ZSB0YWJsZQplbnJpY2htZW50LkRUIDwtIGRhdGF0YWJsZShteUdTRUEudGJsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjYXB0aW9uID0gIGh0bWx0b29sczo6dGFncyRjYXB0aW9uKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlID0gJ2NhcHRpb24tc2lkZTogdG9wOyB0ZXh0LWFsaWduOiBsZWZ0OyBjb2xvcjogYmxhY2snLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGh0bWx0b29sczo6dGFncyRiKCdHZW5lIEZhbWlsaWVzIEVucmljaGVkIGluICcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdzdWIoJy0nLCcgdnMgJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzKGxpc3QubXlUb3BIaXRzLmRmKVtbeXldXSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9XaWR0aCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Nyb2xsWCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI3Njcm9sbFkgPSAnODAwcHgnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbENvbGxhcHNlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWFyY2hIaWdobGlnaHQgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlciA9IGxpc3QoMywgJ2Rlc2MnKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlTGVuZ3RoID0gMjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aE1lbnUgPSBjKCI1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjUwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAwIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uRGVmcyA9IGxpc3QoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KHRhcmdldHMgPSAiX2FsbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPSJkdC1yaWdodCIpKSkpICU+JQogIGZvcm1hdFJvdW5kKGNvbHVtbnM9YygzLDU6NiksIGRpZ2l0cz0yKSAlPiUKICBmb3JtYXRSb3VuZChjb2x1bW5zPWMoNCksIGRpZ2l0cz00KQplbnJpY2htZW50LkRUCgojIGNyZWF0ZSBlbnJpY2htZW50IHBsb3RzIHVzaW5nIHRoZSBlbnJpY2hwbG90IHBhY2thZ2UKIyBnc2VhcGxvdDIobXlHU0VBLnJlcywgCiMgICAgICAgICAgIGdlbmVTZXRJRCA9IDMsICNjYW4gY2hvb3NlIG11bHRpcGxlIHNpZ25hdHVyZXMgdG8gb3ZlcmxheSBpbiB0aGlzIHBsb3QKIyAgICAgICAgICAgcHZhbHVlX3RhYmxlID0gRkFMU0UsICNjYW4gc2V0IHRoaXMgdG8gRkFMU0UgZm9yIGEgY2xlYW5lciBwbG90CiMgICAgICAgICAgIHRpdGxlID0gIlNDUC9UQVAgR2VuZSBTZXQiKSAjY2FuIGFsc28gdHVybiBvZmYgdGhpcyB0aXRsZQoKIyBhZGQgYSB2YXJpYWJsZSB0byB0aGlzIHJlc3VsdCB0aGF0IG1hdGNoZXMgZW5yaWNobWVudCBkaXJlY3Rpb24gd2l0aCBwaGVub3R5cGUKbXlHU0VBLmRmIDwtIG15R1NFQS5kZiAlPiUKICBtdXRhdGUobGlmZV9zdGFnZSA9IGNhc2Vfd2hlbigKICAgIE5FUyA+IDAgfiBzdHJfc3BsaXQobmFtZXMobGlzdC5teVRvcEhpdHMuZGYpW1t5eV1dLCctJyxzaW1wbGlmeSA9IFQpWzEsMV0sCiAgICBORVMgPCAwIH4gc3RyX3NwbGl0KG5hbWVzKGxpc3QubXlUb3BIaXRzLmRmKVtbeXldXSwnLScsc2ltcGxpZnkgPSBUKVsxLDJdKSkKCm15R1NFQS5kZiRJRCA8LSBteUdTRUEuZGYkSUQgJT4lCiAgd29yZChzZXAgPSAnLCcpICU+JQogICN3b3JkKHNlcCA9ICcvJykgJT4lCiAgd29yZChzZXAgPSAnIGFuZCcpCgojIGNyZWF0ZSAnYnViYmxlIHBsb3QnIHRvIHN1bW1hcml6ZSB5IHNpZ25hdHVyZXMgYWNyb3NzIHggcGhlbm90eXBlcwpnZ3Bsb3QobXlHU0VBLmRmLCBhZXMoeD1saWZlX3N0YWdlLCB5PUlEKSkgKyAKICBnZW9tX3BvaW50KGFlcyhzaXplPXNldFNpemUsIGNvbG9yID0gTkVTLCBhbHBoYT0tbG9nMTAocC5hZGp1c3QpKSkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdz0iYmx1ZSIsIGhpZ2g9InJlZCIpICsKICBsYWJzKHRpdGxlID0gcGFzdGUwKCdTLiBwYXBpbGxvc3VzOiBHZW5lIEZhbWlsaWVzIEVucmljaGVkIGluICcsIAogICAgICAgICAgICAgICAgICAgICAgZ3N1YignLScsJyB2cyAnLAogICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyhsaXN0Lm15VG9wSGl0cy5kZilbW3l5XV0pKSwKICAgICAgIHN1YnRpdGxlID0gJ05FUyA9IE5vcm1hbGl6ZWQgRW5yaWNobWVudCBTY29yZTsgR2VuZSBmYW1pbHkgYXNzaWdubWVudHMgCiAgICAgICAgICAgICBmcm9tIEVuc2VtYmwgQ29tcGFyYSBkYXRhc2V0IGRlZmluZWQgaW4gSHVudCBldCBhbCAyMDE2JywKICAgICAgIHggPSAiTGlmZSBTdGFnZSIsCiAgICAgICB5ID0gIkZhbWlseSBJRCIpICsKICAjY29vcmRfZml4ZWQoMS8yKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICBwbG90LmNhcHRpb24ucG9zaXRpb24gPSAicGxvdCIsCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEzLCBoanVzdCA9IDApLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA0LCBoanVzdCA9IDEpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMywgIm1tIiksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLHNpemUgPSAxMC40KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIsc2l6ZSA9IDEwLjQpLAogICAgICAgIGFzcGVjdC5yYXRpbyA9IDMvMSkKCmBgYAoKIyBBcHBlbmRpeCBJOiBBbGwgY29kZSBmb3IgdGhpcyByZXBvcnQgIApgYGB7ciByZWYubGFiZWw9a25pdHI6OmFsbF9sYWJlbHMoKSwgZWNobz1UUlVFLCBldmFsPUZBTFNFfQpgYGAKCgo=